-void ELFFile<ELFT>::LoadVersionDefs(const Elf_Shdr *sec) const {
- unsigned vd_size = sec->sh_size; // Size of section in bytes
- unsigned vd_count = sec->sh_info; // Number of Verdef entries
- const char *sec_start = (const char*)base() + sec->sh_offset;
- const char *sec_end = sec_start + vd_size;
- // The first Verdef entry is at the start of the section.
- const char *p = sec_start;
- for (unsigned i = 0; i < vd_count; i++) {
- if (p + sizeof(Elf_Verdef) > sec_end)
- report_fatal_error("Section ended unexpectedly while scanning "
- "version definitions.");
- const Elf_Verdef *vd = reinterpret_cast<const Elf_Verdef *>(p);
- if (vd->vd_version != ELF::VER_DEF_CURRENT)
- report_fatal_error("Unexpected verdef version");
- size_t index = vd->vd_ndx & ELF::VERSYM_VERSION;
- if (index >= VersionMap.size())
- VersionMap.resize(index + 1);
- VersionMap[index] = VersionMapEntry(vd);
- p += vd->vd_next;
- }
-}
-
-// Iterate through the versions needed section, and place each Elf_Vernaux
-// in the VersionMap according to its index.
-template <class ELFT>
-void ELFFile<ELFT>::LoadVersionNeeds(const Elf_Shdr *sec) const {
- unsigned vn_size = sec->sh_size; // Size of section in bytes
- unsigned vn_count = sec->sh_info; // Number of Verneed entries
- const char *sec_start = (const char *)base() + sec->sh_offset;
- const char *sec_end = sec_start + vn_size;
- // The first Verneed entry is at the start of the section.
- const char *p = sec_start;
- for (unsigned i = 0; i < vn_count; i++) {
- if (p + sizeof(Elf_Verneed) > sec_end)
- report_fatal_error("Section ended unexpectedly while scanning "
- "version needed records.");
- const Elf_Verneed *vn = reinterpret_cast<const Elf_Verneed *>(p);
- if (vn->vn_version != ELF::VER_NEED_CURRENT)
- report_fatal_error("Unexpected verneed version");
- // Iterate through the Vernaux entries
- const char *paux = p + vn->vn_aux;
- for (unsigned j = 0; j < vn->vn_cnt; j++) {
- if (paux + sizeof(Elf_Vernaux) > sec_end)
- report_fatal_error("Section ended unexpected while scanning auxiliary "
- "version needed records.");
- const Elf_Vernaux *vna = reinterpret_cast<const Elf_Vernaux *>(paux);
- size_t index = vna->vna_other & ELF::VERSYM_VERSION;
- if (index >= VersionMap.size())
- VersionMap.resize(index + 1);
- VersionMap[index] = VersionMapEntry(vna);
- paux += vna->vna_next;
- }
- p += vn->vn_next;
- }
-}
-
-template <class ELFT>
-void ELFFile<ELFT>::LoadVersionMap() const {
- // If there is no dynamic symtab or version table, there is nothing to do.
- if (!DotDynSymSec || !dot_gnu_version_sec)
- return;
-
- // Has the VersionMap already been loaded?
- if (VersionMap.size() > 0)
- return;
-
- // The first two version indexes are reserved.
- // Index 0 is LOCAL, index 1 is GLOBAL.
- VersionMap.push_back(VersionMapEntry());
- VersionMap.push_back(VersionMapEntry());
-
- if (dot_gnu_version_d_sec)
- LoadVersionDefs(dot_gnu_version_d_sec);
-
- if (dot_gnu_version_r_sec)
- LoadVersionNeeds(dot_gnu_version_r_sec);
-}