off_t offset,
const elfcpp::Ehdr<size, big_endian>& ehdr)
: Dynobj(name, input_file, offset),
- elf_file_(this, ehdr)
+ elf_file_(this, ehdr),
+ dynsym_shndx_(-1U),
+ symbols_(NULL),
+ defined_count_(0)
{
}
void
Sized_dynobj<size, big_endian>::find_dynsym_sections(
const unsigned char* pshdrs,
- unsigned int* pdynsym_shndx,
unsigned int* pversym_shndx,
unsigned int* pverdef_shndx,
unsigned int* pverneed_shndx,
unsigned int* pdynamic_shndx)
{
- *pdynsym_shndx = -1U;
*pversym_shndx = -1U;
*pverdef_shndx = -1U;
*pverneed_shndx = -1U;
*pdynamic_shndx = -1U;
+ unsigned int xindex_shndx = 0;
+ unsigned int xindex_link = 0;
const unsigned int shnum = this->shnum();
const unsigned char* p = pshdrs;
for (unsigned int i = 0; i < shnum; ++i, p += This::shdr_size)
switch (shdr.get_sh_type())
{
case elfcpp::SHT_DYNSYM:
- pi = pdynsym_shndx;
+ this->dynsym_shndx_ = i;
+ if (xindex_shndx > 0 && xindex_link == i)
+ {
+ Xindex* xindex = new Xindex(this->elf_file_.large_shndx_offset());
+ xindex->read_symtab_xindex<size, big_endian>(this, xindex_shndx,
+ pshdrs);
+ this->set_xindex(xindex);
+ }
+ pi = NULL;
break;
case elfcpp::SHT_GNU_versym:
pi = pversym_shndx;
case elfcpp::SHT_DYNAMIC:
pi = pdynamic_shndx;
break;
+ case elfcpp::SHT_SYMTAB_SHNDX:
+ xindex_shndx = i;
+ xindex_link = this->adjust_shndx(shdr.get_sh_link());
+ if (xindex_link == this->dynsym_shndx_)
+ {
+ Xindex* xindex = new Xindex(this->elf_file_.large_shndx_offset());
+ xindex->read_symtab_xindex<size, big_endian>(this, xindex_shndx,
+ pshdrs);
+ this->set_xindex(xindex);
+ }
+ pi = NULL;
+ break;
default:
pi = NULL;
break;
gold_assert(shdr.get_sh_type() == type);
- if (shdr.get_sh_link() != link)
+ if (this->adjust_shndx(shdr.get_sh_link()) != link)
this->error(_("unexpected link in section %u header: %u != %u"),
- shndx, shdr.get_sh_link(), link);
+ shndx, this->adjust_shndx(shdr.get_sh_link()), link);
*view = this->get_lasting_view(shdr.get_sh_offset(), shdr.get_sh_size(),
- false);
+ true, false);
*view_size = convert_to_section_size_type(shdr.get_sh_size());
*view_info = shdr.get_sh_info();
}
const off_t dynamic_size = dynamicshdr.get_sh_size();
const unsigned char* pdynamic = this->get_view(dynamicshdr.get_sh_offset(),
- dynamic_size, false);
+ dynamic_size, true, false);
- const unsigned int link = dynamicshdr.get_sh_link();
+ const unsigned int link = this->adjust_shndx(dynamicshdr.get_sh_link());
if (link != strtab_shndx)
{
if (link >= this->shnum())
}
strtab_size = strtabshdr.get_sh_size();
- strtabu = this->get_view(strtabshdr.get_sh_offset(), strtab_size, false);
+ strtabu = this->get_view(strtabshdr.get_sh_offset(), strtab_size, false,
+ false);
}
const char* const strtab = reinterpret_cast<const char*>(strtabu);
const unsigned char* const pshdrs = sd->section_headers->data();
- unsigned int dynsym_shndx;
unsigned int versym_shndx;
unsigned int verdef_shndx;
unsigned int verneed_shndx;
unsigned int dynamic_shndx;
- this->find_dynsym_sections(pshdrs, &dynsym_shndx, &versym_shndx,
- &verdef_shndx, &verneed_shndx, &dynamic_shndx);
+ this->find_dynsym_sections(pshdrs, &versym_shndx, &verdef_shndx,
+ &verneed_shndx, &dynamic_shndx);
unsigned int strtab_shndx = -1U;
sd->symbol_names = NULL;
sd->symbol_names_size = 0;
- if (dynsym_shndx != -1U)
+ if (this->dynsym_shndx_ != -1U)
{
// Get the dynamic symbols.
- typename This::Shdr dynsymshdr(pshdrs + dynsym_shndx * This::shdr_size);
+ typename This::Shdr dynsymshdr(pshdrs
+ + this->dynsym_shndx_ * This::shdr_size);
gold_assert(dynsymshdr.get_sh_type() == elfcpp::SHT_DYNSYM);
sd->symbols = this->get_lasting_view(dynsymshdr.get_sh_offset(),
- dynsymshdr.get_sh_size(), false);
+ dynsymshdr.get_sh_size(), true,
+ false);
sd->symbols_size =
convert_to_section_size_type(dynsymshdr.get_sh_size());
// Get the symbol names.
- strtab_shndx = dynsymshdr.get_sh_link();
+ strtab_shndx = this->adjust_shndx(dynsymshdr.get_sh_link());
if (strtab_shndx >= this->shnum())
{
this->error(_("invalid dynamic symbol table name index: %u"),
sd->symbol_names = this->get_lasting_view(strtabshdr.get_sh_offset(),
strtabshdr.get_sh_size(),
- false);
+ false, false);
sd->symbol_names_size =
convert_to_section_size_type(strtabshdr.get_sh_size());
unsigned int dummy;
this->read_dynsym_section(pshdrs, versym_shndx, elfcpp::SHT_GNU_versym,
- dynsym_shndx, &sd->versym, &sd->versym_size,
- &dummy);
+ this->dynsym_shndx_,
+ &sd->versym, &sd->versym_size, &dummy);
// We require that the version definition and need section link
// to the same string table as the dynamic symbol table. This
sd->symbol_names_size);
}
+// Return the Xindex structure to use for object with lots of
+// sections.
+
+template<int size, bool big_endian>
+Xindex*
+Sized_dynobj<size, big_endian>::do_initialize_xindex()
+{
+ gold_assert(this->dynsym_shndx_ != -1U);
+ Xindex* xindex = new Xindex(this->elf_file_.large_shndx_offset());
+ xindex->initialize_symtab_xindex<size, big_endian>(this, this->dynsym_shndx_);
+ return xindex;
+}
+
// Lay out the input sections for a dynamic object. We don't want to
// include sections from a dynamic object, so all that we actually do
// here is check for .gnu.warning sections.
template<int size, bool big_endian>
void
Sized_dynobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
- Read_symbols_data* sd)
+ Read_symbols_data* sd,
+ Layout*)
{
if (sd->symbols == NULL)
{
Version_map version_map;
this->make_version_map(sd, &version_map);
+ // If printing symbol counts, we want to track symbols.
+
+ if (parameters->options().user_set_print_symbol_counts())
+ {
+ this->symbols_ = new Symbols();
+ this->symbols_->resize(symcount);
+ }
+
const char* sym_names =
reinterpret_cast<const char*>(sd->symbol_names->data());
symtab->add_from_dynobj(this, sd->symbols->data(), symcount,
? NULL
: sd->versym->data()),
sd->versym_size,
- &version_map);
+ &version_map,
+ this->symbols_,
+ &this->defined_count_);
delete sd->symbols;
sd->symbols = NULL;
this->clear_view_cache_marks();
}
+// Get symbol counts.
+
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::do_get_global_symbol_counts(
+ const Symbol_table*,
+ size_t* defined,
+ size_t* used) const
+{
+ *defined = this->defined_count_;
+ size_t count = 0;
+ for (typename Symbols::const_iterator p = this->symbols_->begin();
+ p != this->symbols_->end();
+ ++p)
+ if (*p != NULL
+ && (*p)->source() == Symbol::FROM_OBJECT
+ && (*p)->object() == this
+ && (*p)->is_defined()
+ && (*p)->dynsym_index() != -1U)
+ ++count;
+ *used = count;
+}
+
// Given a vector of hash codes, compute the number of hash buckets to
// use.
// based on the number of symbols there are. If there are fewer
// than 3 symbols we use 1 bucket, fewer than 17 symbols we use 3
// buckets, fewer than 37 we use 17 buckets, and so forth. We never
- // use more than 32771 buckets. This is straight from the old GNU
+ // use more than 262147 buckets. This is straight from the old GNU
// linker.
static const unsigned int buckets[] =
{
1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, 2053, 4099, 8209,
- 16411, 32771
+ 16411, 32771, 65537, 131101, 262147
};
const int buckets_count = sizeof buckets / sizeof buckets[0];
unsigned int symcount = hashcodes.size();
unsigned int ret = 1;
+ const double full_fraction
+ = 1.0 - parameters->options().hash_bucket_empty_fraction();
for (int i = 0; i < buckets_count; ++i)
{
- if (symcount < buckets[i])
+ if (symcount < buckets[i] * full_fraction)
break;
ret = buckets[i];
}
* 4);
unsigned char* phash = new unsigned char[hashlen];
- if (parameters->is_big_endian())
+ if (parameters->target().is_big_endian())
{
#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
Dynobj::sized_create_elf_hash_table<true>(bucket, chain, phash,
// For the actual data generation we call out to a templatized
// function.
- int size = parameters->get_size();
- bool big_endian = parameters->is_big_endian();
+ int size = parameters->target().get_size();
+ bool big_endian = parameters->target().is_big_endian();
if (size == 32)
{
if (big_endian)
template<int size, bool big_endian>
unsigned char*
-Verdef::write(const Stringpool* dynpool, bool is_last, unsigned char* pb
- ACCEPT_SIZE_ENDIAN) const
+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;
template<int size, bool big_endian>
unsigned char*
Verneed::write(const Stringpool* dynpool, bool is_last,
- unsigned char* pb ACCEPT_SIZE_ENDIAN) const
+ unsigned char* pb) const
{
const int verneed_size = elfcpp::Elf_sizes<size>::verneed_size;
const int vernaux_size = elfcpp::Elf_sizes<size>::vernaux_size;
: defs_(), needs_(), version_table_(),
is_finalized_(false), version_script_(version_script)
{
- // We always need a base version, so define that first. Nothing
+ // We always need a base version, so define that first. Nothing
// explicitly declares itself as part of base, so it doesn't need to
- // be in version_table_.
- // FIXME: Should use soname here when creating a shared object. Is
- // this fixme still valid? It looks like it's doing the right thing
- // to me.
- if (parameters->output_is_shared())
+ // be in version_table_.
+ if (parameters->options().shared())
{
- const char* name = dynpool->add(parameters->output_file_name(),
- false, NULL);
+ const char* name = parameters->options().soname();
+ if (name == NULL)
+ name = parameters->options().output_file_name();
+ name = dynpool->add(name, false, NULL);
Verdef* vdbase = new Verdef(name, std::vector<std::string>(),
true, false, true);
this->defs_.push_back(vdbase);
{
gold_assert(!this->is_finalized_);
gold_assert(sym->version() != NULL);
-
+
Stringpool::Key version_key;
const char* version = dynpool->add(sym->version(), false, &version_key);
if (!sym->is_from_dynobj() && !sym->is_copied_from_dynobj())
{
- if (parameters->output_is_shared())
+ if (parameters->options().shared())
this->add_def(sym, version, version_key);
}
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 (parameters->output_is_shared())
- {
- gold_error(_("symbol %s has undefined version %s"),
- sym->demangled_name().c_str(), version);
- return;
- }
+ if (parameters->options().shared())
+ gold_error(_("symbol %s has undefined version %s"),
+ sym->demangled_name().c_str(), version);
// When creating a regular executable, automatically define
// a new version.
Key k;
if (!sym->is_from_dynobj() && !sym->is_copied_from_dynobj())
{
- if (!parameters->output_is_shared())
+ if (!parameters->options().shared())
return elfcpp::VER_NDX_GLOBAL;
k = Key(version_key, 0);
}
unsigned int local_symcount,
const std::vector<Symbol*>& syms,
unsigned char** pp,
- unsigned int* psize
- ACCEPT_SIZE_ENDIAN) const
+ unsigned int* psize) const
{
gold_assert(this->is_finalized_);
void
Versions::def_section_contents(const Stringpool* dynpool,
unsigned char** pp, unsigned int* psize,
- unsigned int* pentries
- ACCEPT_SIZE_ENDIAN) const
+ unsigned int* pentries) const
{
gold_assert(this->is_finalized_);
gold_assert(!this->defs_.empty());
for (p = this->defs_.begin(), i = 0;
p != this->defs_.end();
++p, ++i)
- pb = (*p)->write SELECT_SIZE_ENDIAN_NAME(size, big_endian)(
- dynpool, i + 1 >= this->defs_.size(), pb
- SELECT_SIZE_ENDIAN(size, big_endian));
+ pb = (*p)->write<size, big_endian>(dynpool,
+ i + 1 >= this->defs_.size(),
+ pb);
gold_assert(static_cast<unsigned int>(pb - pbuf) == sz);
void
Versions::need_section_contents(const Stringpool* dynpool,
unsigned char** pp, unsigned int *psize,
- unsigned int *pentries
- ACCEPT_SIZE_ENDIAN) const
+ unsigned int *pentries) const
{
gold_assert(this->is_finalized_);
gold_assert(!this->needs_.empty());
for (p = this->needs_.begin(), i = 0;
p != this->needs_.end();
++p, ++i)
- pb = (*p)->write SELECT_SIZE_ENDIAN_NAME(size, big_endian)(
- dynpool, i + 1 >= this->needs_.size(), pb
- SELECT_SIZE_ENDIAN(size, big_endian));
+ pb = (*p)->write<size, big_endian>(dynpool,
+ i + 1 >= this->needs_.size(),
+ pb);
gold_assert(static_cast<unsigned int>(pb - pbuf) == sz);
unsigned int,
const std::vector<Symbol*>&,
unsigned char**,
- unsigned int*
- ACCEPT_SIZE_ENDIAN_EXPLICIT(32, false)) const;
+ unsigned int*) const;
#endif
#ifdef HAVE_TARGET_32_BIG
unsigned int,
const std::vector<Symbol*>&,
unsigned char**,
- unsigned int*
- ACCEPT_SIZE_ENDIAN_EXPLICIT(32, true)) const;
+ unsigned int*) const;
#endif
#ifdef HAVE_TARGET_64_LITTLE
unsigned int,
const std::vector<Symbol*>&,
unsigned char**,
- unsigned int*
- ACCEPT_SIZE_ENDIAN_EXPLICIT(64, false)) const;
+ unsigned int*) const;
#endif
#ifdef HAVE_TARGET_64_BIG
unsigned int,
const std::vector<Symbol*>&,
unsigned char**,
- unsigned int*
- ACCEPT_SIZE_ENDIAN_EXPLICIT(64, true)) const;
+ unsigned int*) const;
#endif
#ifdef HAVE_TARGET_32_LITTLE
const Stringpool*,
unsigned char**,
unsigned int*,
- unsigned int*
- ACCEPT_SIZE_ENDIAN_EXPLICIT(32, false)) const;
+ unsigned int*) const;
#endif
#ifdef HAVE_TARGET_32_BIG
const Stringpool*,
unsigned char**,
unsigned int*,
- unsigned int*
- ACCEPT_SIZE_ENDIAN_EXPLICIT(32, true)) const;
+ unsigned int*) const;
#endif
#ifdef HAVE_TARGET_64_LITTLE
const Stringpool*,
unsigned char**,
unsigned int*,
- unsigned int*
- ACCEPT_SIZE_ENDIAN_EXPLICIT(64, false)) const;
+ unsigned int*) const;
#endif
#ifdef HAVE_TARGET_64_BIG
const Stringpool*,
unsigned char**,
unsigned int*,
- unsigned int*
- ACCEPT_SIZE_ENDIAN_EXPLICIT(64, true)) const;
+ unsigned int*) const;
#endif
#ifdef HAVE_TARGET_32_LITTLE
const Stringpool*,
unsigned char**,
unsigned int*,
- unsigned int*
- ACCEPT_SIZE_ENDIAN_EXPLICIT(32, false)) const;
+ unsigned int*) const;
#endif
#ifdef HAVE_TARGET_32_BIG
const Stringpool*,
unsigned char**,
unsigned int*,
- unsigned int*
- ACCEPT_SIZE_ENDIAN_EXPLICIT(32, true)) const;
+ unsigned int*) const;
#endif
#ifdef HAVE_TARGET_64_LITTLE
const Stringpool*,
unsigned char**,
unsigned int*,
- unsigned int*
- ACCEPT_SIZE_ENDIAN_EXPLICIT(64, false)) const;
+ unsigned int*) const;
#endif
#ifdef HAVE_TARGET_64_BIG
const Stringpool*,
unsigned char**,
unsigned int*,
- unsigned int*
- ACCEPT_SIZE_ENDIAN_EXPLICIT(64, true)) const;
+ unsigned int*) const;
#endif
} // End namespace gold.