+// Add all the symbols in a dynamic object to the hash table.
+
+template<int size, bool big_endian>
+void
+Symbol_table::add_from_dynobj(
+ Sized_dynobj<size, big_endian>* dynobj,
+ const unsigned char* syms,
+ size_t count,
+ const char* sym_names,
+ size_t sym_name_size,
+ const unsigned char* versym,
+ size_t versym_size,
+ const std::vector<const char*>* version_map)
+{
+ // We take the size from the first object we see.
+ if (this->get_size() == 0)
+ this->set_size(size);
+
+ if (size != this->get_size() || size != dynobj->target()->get_size())
+ {
+ fprintf(stderr, _("%s: %s: mixing 32-bit and 64-bit ELF objects\n"),
+ program_name, dynobj->name().c_str());
+ gold_exit(false);
+ }
+
+ if (versym != NULL && versym_size / 2 < count)
+ {
+ fprintf(stderr, _("%s: %s: too few symbol versions\n"),
+ program_name, dynobj->name().c_str());
+ gold_exit(false);
+ }
+
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+
+ const unsigned char* p = syms;
+ const unsigned char* vs = versym;
+ for (size_t i = 0; i < count; ++i, p += sym_size, vs += 2)
+ {
+ elfcpp::Sym<size, big_endian> sym(p);
+
+ // Ignore symbols with local binding.
+ if (sym.get_st_bind() == elfcpp::STB_LOCAL)
+ continue;
+
+ unsigned int st_name = sym.get_st_name();
+ if (st_name >= sym_name_size)
+ {
+ fprintf(stderr, _("%s: %s: bad symbol name offset %u at %lu\n"),
+ program_name, dynobj->name().c_str(), st_name,
+ static_cast<unsigned long>(i));
+ gold_exit(false);
+ }
+
+ const char* name = sym_names + st_name;
+
+ if (versym == NULL)
+ {
+ Stringpool::Key name_key;
+ name = this->namepool_.add(name, &name_key);
+ this->add_from_object(dynobj, name, name_key, NULL, 0,
+ false, sym);
+ continue;
+ }
+
+ // Read the version information.
+
+ unsigned int v = elfcpp::Swap<16, big_endian>::readval(vs);
+
+ bool hidden = (v & elfcpp::VERSYM_HIDDEN) != 0;
+ v &= elfcpp::VERSYM_VERSION;
+
+ if (v == static_cast<unsigned int>(elfcpp::VER_NDX_LOCAL))
+ {
+ // This symbol should not be visible outside the object.
+ continue;
+ }
+
+ // At this point we are definitely going to add this symbol.
+ Stringpool::Key name_key;
+ name = this->namepool_.add(name, &name_key);
+
+ if (v == static_cast<unsigned int>(elfcpp::VER_NDX_GLOBAL))
+ {
+ // This symbol does not have a version.
+ this->add_from_object(dynobj, name, name_key, NULL, 0, false, sym);
+ continue;
+ }
+
+ if (v >= version_map->size())
+ {
+ fprintf(stderr,
+ _("%s: %s: versym for symbol %zu out of range: %u\n"),
+ program_name, dynobj->name().c_str(), i, v);
+ gold_exit(false);
+ }
+
+ const char* version = (*version_map)[v];
+ if (version == NULL)
+ {
+ fprintf(stderr, _("%s: %s: versym for symbol %zu has no name: %u\n"),
+ program_name, dynobj->name().c_str(), i, v);
+ gold_exit(false);
+ }
+
+ Stringpool::Key version_key;
+ version = this->namepool_.add(version, &version_key);
+
+ // If this is an absolute symbol, and the version name and
+ // symbol name are the same, then this is the version definition
+ // symbol. These symbols exist to support using -u to pull in
+ // particular versions. We do not want to record a version for
+ // them.
+ if (sym.get_st_shndx() == elfcpp::SHN_ABS && name_key == version_key)
+ {
+ this->add_from_object(dynobj, name, name_key, NULL, 0, false, sym);
+ continue;
+ }
+
+ const bool def = !hidden && sym.get_st_shndx() != elfcpp::SHN_UNDEF;
+
+ this->add_from_object(dynobj, name, name_key, version, version_key,
+ def, sym);
+ }
+}
+