[ELF] - Recommit r273143("[ELF] - Basic versioned symbols support implemented.")

With fix:
-soname flag was not set in testcase. Hash calculated for base def was different on local
and bot machines because filename fos used for calculating.

Initial commit message:
Patch implements basic support of versioned symbols.
There is no wildcards patterns matching except local: *;
There is no support for hierarchies.
There is no support for symbols overrides (@ vs @@ not handled).

This patch allows programs that using simple scripts to link and run.

Differential revision: http://reviews.llvm.org/D21018

llvm-svn: 273152
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index 4b71874..2f0bd9e 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -591,6 +591,11 @@
     V.push_back({Sym.Body, Sym.STName});
 }
 
+// Returns the number of version definition entries. Because the first entry
+// is for the version definition itself, it is the number of versioned symbols
+// plus one. Note that we don't support multiple versions yet.
+static unsigned getVerDefNum() { return Config->SymbolVersions.size() + 1; }
+
 template <class ELFT>
 DynamicSection<ELFT>::DynamicSection()
     : OutputSectionBase<ELFT>(".dynamic", SHT_DYNAMIC, SHF_ALLOC | SHF_WRITE) {
@@ -693,10 +698,16 @@
   if (!Config->Entry.empty())
     Add({DT_DEBUG, (uint64_t)0});
 
-  if (size_t NeedNum = Out<ELFT>::VerNeed->getNeedNum()) {
+  bool HasVerNeed = Out<ELFT>::VerNeed->getNeedNum() != 0;
+  if (HasVerNeed || Out<ELFT>::VerDef)
     Add({DT_VERSYM, Out<ELFT>::VerSym});
+  if (Out<ELFT>::VerDef) {
+    Add({DT_VERDEF, Out<ELFT>::VerDef});
+    Add({DT_VERDEFNUM, getVerDefNum()});
+  }
+  if (HasVerNeed) {
     Add({DT_VERNEED, Out<ELFT>::VerNeed});
-    Add({DT_VERNEEDNUM, NeedNum});
+    Add({DT_VERNEEDNUM, Out<ELFT>::VerNeed->getNeedNum()});
   }
 
   if (Config->EMachine == EM_MIPS) {
@@ -1435,6 +1446,68 @@
 }
 
 template <class ELFT>
+VersionDefinitionSection<ELFT>::VersionDefinitionSection()
+    : OutputSectionBase<ELFT>(".gnu.version_d", SHT_GNU_verdef, SHF_ALLOC) {}
+
+static StringRef getFileDefName() {
+  if (!Config->SoName.empty())
+    return Config->SoName;
+  return Config->OutputFile;
+}
+
+template <class ELFT> void VersionDefinitionSection<ELFT>::finalize() {
+  FileDefNameOff = Out<ELFT>::DynStrTab->addString(getFileDefName());
+  for (Version &V : Config->SymbolVersions)
+    V.NameOff = Out<ELFT>::DynStrTab->addString(V.Name);
+
+  this->Header.sh_size =
+      (sizeof(Elf_Verdef) + sizeof(Elf_Verdaux)) * getVerDefNum();
+  this->Header.sh_link = Out<ELFT>::DynStrTab->SectionIndex;
+  this->Header.sh_addralign = sizeof(uint32_t);
+
+  // sh_info should be set to the number of definitions. This fact is missed in
+  // documentation, but confirmed by binutils community:
+  // https://sourceware.org/ml/binutils/2014-11/msg00355.html
+  this->Header.sh_info = getVerDefNum();
+}
+
+template <class Elf_Verdef, class Elf_Verdaux>
+static void writeDefinition(Elf_Verdef *&Verdef, Elf_Verdaux *&Verdaux,
+                            uint32_t Flags, uint32_t Index, StringRef Name,
+                            size_t StrTabOffset) {
+  Verdef->vd_version = 1;
+  Verdef->vd_cnt = 1;
+  Verdef->vd_aux =
+      reinterpret_cast<char *>(Verdaux) - reinterpret_cast<char *>(Verdef);
+  Verdef->vd_next = sizeof(Elf_Verdef);
+
+  Verdef->vd_flags = Flags;
+  Verdef->vd_ndx = Index;
+  Verdef->vd_hash = hashSysv(Name);
+  ++Verdef;
+
+  Verdaux->vda_name = StrTabOffset;
+  Verdaux->vda_next = 0;
+  ++Verdaux;
+}
+
+template <class ELFT>
+void VersionDefinitionSection<ELFT>::writeTo(uint8_t *Buf) {
+  Elf_Verdef *Verdef = reinterpret_cast<Elf_Verdef *>(Buf);
+  Elf_Verdaux *Verdaux =
+      reinterpret_cast<Elf_Verdaux *>(Verdef + getVerDefNum());
+
+  writeDefinition(Verdef, Verdaux, VER_FLG_BASE, 1, getFileDefName(),
+                  FileDefNameOff);
+
+  uint32_t I = 2;
+  for (Version &V : Config->SymbolVersions)
+    writeDefinition(Verdef, Verdaux, 0 /* Flags */, I++, V.Name, V.NameOff);
+
+  Verdef[-1].vd_next = 0;
+}
+
+template <class ELFT>
 VersionTableSection<ELFT>::VersionTableSection()
     : OutputSectionBase<ELFT>(".gnu.version", SHT_GNU_versym, SHF_ALLOC) {
   this->Header.sh_addralign = sizeof(uint16_t);
@@ -1453,10 +1526,7 @@
   auto *OutVersym = reinterpret_cast<Elf_Versym *>(Buf) + 1;
   for (const std::pair<SymbolBody *, size_t> &P :
        Out<ELFT>::DynSymTab->getSymbols()) {
-    if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(P.first))
-      OutVersym->vs_index = SS->VersionId;
-    else
-      OutVersym->vs_index = VER_NDX_GLOBAL;
+    OutVersym->vs_index = P.first->symbol()->VersionId;
     ++OutVersym;
   }
 }
@@ -1465,12 +1535,17 @@
 VersionNeedSection<ELFT>::VersionNeedSection()
     : OutputSectionBase<ELFT>(".gnu.version_r", SHT_GNU_verneed, SHF_ALLOC) {
   this->Header.sh_addralign = sizeof(uint32_t);
+
+  // Identifiers in verneed section start at 2 because 0 and 1 are reserved
+  // for VER_NDX_LOCAL and VER_NDX_GLOBAL.
+  // First identifiers are reserved by verdef section if it exist.
+  NextIndex = getVerDefNum() + 1;
 }
 
 template <class ELFT>
 void VersionNeedSection<ELFT>::addSymbol(SharedSymbol<ELFT> *SS) {
   if (!SS->Verdef) {
-    SS->VersionId = VER_NDX_GLOBAL;
+    SS->symbol()->VersionId = VER_NDX_GLOBAL;
     return;
   }
   SharedFile<ELFT> *F = SS->File;
@@ -1488,7 +1563,7 @@
         SS->File->getStringTable().data() + SS->Verdef->getAux()->vda_name);
     NV.Index = NextIndex++;
   }
-  SS->VersionId = NV.Index;
+  SS->symbol()->VersionId = NV.Index;
 }
 
 template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) {
@@ -1744,6 +1819,11 @@
 template class VersionNeedSection<ELF64LE>;
 template class VersionNeedSection<ELF64BE>;
 
+template class VersionDefinitionSection<ELF32LE>;
+template class VersionDefinitionSection<ELF32BE>;
+template class VersionDefinitionSection<ELF64LE>;
+template class VersionDefinitionSection<ELF64BE>;
+
 template class BuildIdSection<ELF32LE>;
 template class BuildIdSection<ELF32BE>;
 template class BuildIdSection<ELF64LE>;