[lld] r267775 - ELF: Create .gnu.version and .gnu.version_r sections when linking against versioned DSOs.

Peter Collingbourne via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 27 13:22:31 PDT 2016


Author: pcc
Date: Wed Apr 27 15:22:31 2016
New Revision: 267775

URL: http://llvm.org/viewvc/llvm-project?rev=267775&view=rev
Log:
ELF: Create .gnu.version and .gnu.version_r sections when linking against versioned DSOs.

Differential Revision: http://reviews.llvm.org/D19464

Added:
    lld/trunk/test/ELF/Inputs/verneed.so.sh   (with props)
    lld/trunk/test/ELF/Inputs/verneed1.so   (with props)
    lld/trunk/test/ELF/Inputs/verneed2.so   (with props)
    lld/trunk/test/ELF/verneed-local.s
    lld/trunk/test/ELF/verneed.s
Modified:
    lld/trunk/ELF/InputFiles.cpp
    lld/trunk/ELF/InputFiles.h
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/ELF/Symbols.h
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=267775&r1=267774&r2=267775&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.cpp (original)
+++ lld/trunk/ELF/InputFiles.cpp Wed Apr 27 15:22:31 2016
@@ -407,6 +407,12 @@ template <class ELFT> void SharedFile<EL
     case SHT_SYMTAB_SHNDX:
       this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec));
       break;
+    case SHT_GNU_versym:
+      this->VersymSec = &Sec;
+      break;
+    case SHT_GNU_verdef:
+      this->VerdefSec = &Sec;
+      break;
     }
   }
 
@@ -430,17 +436,70 @@ template <class ELFT> void SharedFile<EL
   }
 }
 
+// Parse the version definitions in the object file if present. Returns a vector
+// whose nth element contains a pointer to the Elf_Verdef for version identifier
+// n. Version identifiers that are not definitions map to nullptr. The array
+// always has at least length 1.
+template <class ELFT>
+std::vector<const typename ELFT::Verdef *>
+SharedFile<ELFT>::parseVerdefs(const Elf_Versym *&Versym) {
+  std::vector<const Elf_Verdef *> Verdefs(1);
+  // We only need to process symbol versions for this DSO if it has both a
+  // versym and a verdef section, which indicates that the DSO contains symbol
+  // version definitions.
+  if (!VersymSec || !VerdefSec)
+    return Verdefs;
+
+  // The location of the first global versym entry.
+  Versym = reinterpret_cast<const Elf_Versym *>(this->ELFObj.base() +
+                                                VersymSec->sh_offset) +
+           this->Symtab->sh_info;
+
+  // We cannot determine the largest verdef identifier without inspecting
+  // every Elf_Verdef, but both bfd and gold assign verdef identifiers
+  // sequentially starting from 1, so we predict that the largest identifier
+  // will be VerdefCount.
+  unsigned VerdefCount = VerdefSec->sh_info;
+  Verdefs.resize(VerdefCount + 1);
+
+  // Build the Verdefs array by following the chain of Elf_Verdef objects
+  // from the start of the .gnu.version_d section.
+  const uint8_t *Verdef = this->ELFObj.base() + VerdefSec->sh_offset;
+  for (unsigned I = 0; I != VerdefCount; ++I) {
+    auto *CurVerdef = reinterpret_cast<const Elf_Verdef *>(Verdef);
+    Verdef += CurVerdef->vd_next;
+    unsigned VerdefIndex = CurVerdef->vd_ndx;
+    if (Verdefs.size() <= VerdefIndex)
+      Verdefs.resize(VerdefIndex + 1);
+    Verdefs[VerdefIndex] = CurVerdef;
+  }
+
+  return Verdefs;
+}
+
 // Fully parse the shared object file. This must be called after parseSoName().
 template <class ELFT> void SharedFile<ELFT>::parseRest() {
+  // Create mapping from version identifiers to Elf_Verdef entries.
+  const Elf_Versym *Versym = nullptr;
+  std::vector<const Elf_Verdef *> Verdefs = parseVerdefs(Versym);
+
   Elf_Sym_Range Syms = this->getElfSymbols(true);
   uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
   SymbolBodies.reserve(NumSymbols);
   for (const Elf_Sym &Sym : Syms) {
+    unsigned VersymIndex = 0;
+    if (Versym) {
+      VersymIndex = Versym->vs_index;
+      ++Versym;
+      // Ignore local symbols and non-default versions.
+      if (VersymIndex == 0 || (VersymIndex & VERSYM_HIDDEN))
+        continue;
+    }
     StringRef Name = check(Sym.getName(this->StringTable));
     if (Sym.isUndefined())
       Undefs.push_back(Name);
     else
-      SymbolBodies.emplace_back(this, Name, Sym);
+      SymbolBodies.emplace_back(this, Name, Sym, Verdefs[VersymIndex]);
   }
 }
 

Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=267775&r1=267774&r2=267775&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Wed Apr 27 15:22:31 2016
@@ -24,6 +24,8 @@
 #include "llvm/Object/IRObjectFile.h"
 #include "llvm/Support/StringSaver.h"
 
+#include <map>
+
 namespace lld {
 namespace elf {
 
@@ -245,10 +247,14 @@ template <class ELFT> class SharedFile :
   typedef typename ELFT::Sym Elf_Sym;
   typedef typename ELFT::Word Elf_Word;
   typedef typename ELFT::SymRange Elf_Sym_Range;
+  typedef typename ELFT::Versym Elf_Versym;
+  typedef typename ELFT::Verdef Elf_Verdef;
 
   std::vector<SharedSymbol<ELFT>> SymbolBodies;
   std::vector<StringRef> Undefs;
   StringRef SoName;
+  const Elf_Shdr *VersymSec = nullptr;
+  const Elf_Shdr *VerdefSec = nullptr;
 
 public:
   StringRef getSoName() const { return SoName; }
@@ -266,6 +272,19 @@ public:
 
   void parseSoName();
   void parseRest();
+  std::vector<const Elf_Verdef *> parseVerdefs(const Elf_Versym *&Versym);
+
+  struct NeededVer {
+    // The string table offset of the version name in the output file.
+    size_t StrTab;
+
+    // The version identifier for this version name.
+    uint16_t Index;
+  };
+
+  // Mapping from Elf_Verdef data structures to information about Elf_Vernaux
+  // data structures in the output file.
+  std::map<const Elf_Verdef *, NeededVer> VerdefMap;
 
   // Used for --as-needed
   bool AsNeeded = false;

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=267775&r1=267774&r2=267775&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Wed Apr 27 15:22:31 2016
@@ -654,6 +654,12 @@ template <class ELFT> void DynamicSectio
   if (!Config->Entry.empty())
     Add({DT_DEBUG, (uint64_t)0});
 
+  if (size_t NeedNum = Out<ELFT>::VerNeed->getNeedNum()) {
+    Add({DT_VERSYM, Out<ELFT>::VerSym});
+    Add({DT_VERNEED, Out<ELFT>::VerNeed});
+    Add({DT_VERNEEDNUM, NeedNum});
+  }
+
   if (Config->EMachine == EM_MIPS) {
     Add({DT_MIPS_RLD_VERSION, 1});
     Add({DT_MIPS_FLAGS, RHF_NOTPOT});
@@ -1514,6 +1520,102 @@ SymbolTableSection<ELFT>::getOutputSecti
 }
 
 template <class ELFT>
+VersionTableSection<ELFT>::VersionTableSection()
+    : OutputSectionBase<ELFT>(".gnu.version", SHT_GNU_versym, SHF_ALLOC) {}
+
+template <class ELFT> void VersionTableSection<ELFT>::finalize() {
+  this->Header.sh_size =
+      sizeof(Elf_Versym) * (Out<ELFT>::DynSymTab->getSymbols().size() + 1);
+  this->Header.sh_entsize = sizeof(Elf_Versym);
+}
+
+template <class ELFT> void VersionTableSection<ELFT>::writeTo(uint8_t *Buf) {
+  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
+      // The reserved identifier for a non-versioned global symbol.
+      OutVersym->vs_index = 1;
+    ++OutVersym;
+  }
+}
+
+template <class ELFT>
+VersionNeedSection<ELFT>::VersionNeedSection()
+    : OutputSectionBase<ELFT>(".gnu.version_r", SHT_GNU_verneed, SHF_ALLOC) {}
+
+template <class ELFT>
+void VersionNeedSection<ELFT>::addSymbol(SharedSymbol<ELFT> *SS) {
+  if (!SS->Verdef) {
+    // The reserved identifier for a non-versioned global symbol.
+    SS->VersionId = 1;
+    return;
+  }
+  SharedFile<ELFT> *F = SS->File;
+  // If we don't already know that we need an Elf_Verneed for this DSO, prepare
+  // to create one by adding it to our needed list and creating a dynstr entry
+  // for the soname.
+  if (F->VerdefMap.empty())
+    Needed.push_back({F, Out<ELFT>::DynStrTab->addString(F->getSoName())});
+  typename SharedFile<ELFT>::NeededVer &NV = F->VerdefMap[SS->Verdef];
+  // If we don't already know that we need an Elf_Vernaux for this Elf_Verdef,
+  // prepare to create one by allocating a version identifier and creating a
+  // dynstr entry for the version name.
+  if (NV.Index == 0) {
+    NV.StrTab = Out<ELFT>::DynStrTab->addString(
+        SS->File->getStringTable().data() + SS->Verdef->getAux()->vda_name);
+    NV.Index = NextIndex++;
+  }
+  SS->VersionId = NV.Index;
+}
+
+template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) {
+  // The Elf_Verneeds need to appear first, followed by the Elf_Vernauxs.
+  auto *Verneed = reinterpret_cast<Elf_Verneed *>(Buf);
+  auto *Vernaux = reinterpret_cast<Elf_Vernaux *>(Verneed + Needed.size());
+
+  for (std::pair<SharedFile<ELFT> *, size_t> &P : Needed) {
+    // Create an Elf_Verneed for this DSO.
+    Verneed->vn_version = 1;
+    Verneed->vn_cnt = P.first->VerdefMap.size();
+    Verneed->vn_file = P.second;
+    Verneed->vn_aux =
+        reinterpret_cast<char *>(Vernaux) - reinterpret_cast<char *>(Verneed);
+    Verneed->vn_next = sizeof(Elf_Verneed);
+    ++Verneed;
+
+    // Create the Elf_Vernauxs for this Elf_Verneed. The loop iterates over
+    // VerdefMap, which will only contain references to needed version
+    // definitions. Each Elf_Vernaux is based on the information contained in
+    // the Elf_Verdef in the source DSO. This loop iterates over a std::map of
+    // pointers, but is deterministic because the pointers refer to Elf_Verdef
+    // data structures within a single input file.
+    for (auto &NV : P.first->VerdefMap) {
+      Vernaux->vna_hash = NV.first->vd_hash;
+      Vernaux->vna_flags = 0;
+      Vernaux->vna_other = NV.second.Index;
+      Vernaux->vna_name = NV.second.StrTab;
+      Vernaux->vna_next = sizeof(Elf_Vernaux);
+      ++Vernaux;
+    }
+
+    Vernaux[-1].vna_next = 0;
+  }
+  Verneed[-1].vn_next = 0;
+}
+
+template <class ELFT> void VersionNeedSection<ELFT>::finalize() {
+  this->Header.sh_link = Out<ELFT>::DynStrTab->SectionIndex;
+  this->Header.sh_info = Needed.size();
+  unsigned Size = Needed.size() * sizeof(Elf_Verneed);
+  for (std::pair<SharedFile<ELFT> *, size_t> &P : Needed)
+    Size += P.first->VerdefMap.size() * sizeof(Elf_Vernaux);
+  this->Header.sh_size = Size;
+}
+
+template <class ELFT>
 BuildIdSection<ELFT>::BuildIdSection(size_t HashSize)
     : OutputSectionBase<ELFT>(".note.gnu.build-id", SHT_NOTE, SHF_ALLOC),
       HashSize(HashSize) {
@@ -1666,6 +1768,16 @@ template class SymbolTableSection<ELF32B
 template class SymbolTableSection<ELF64LE>;
 template class SymbolTableSection<ELF64BE>;
 
+template class VersionTableSection<ELF32LE>;
+template class VersionTableSection<ELF32BE>;
+template class VersionTableSection<ELF64LE>;
+template class VersionTableSection<ELF64BE>;
+
+template class VersionNeedSection<ELF32LE>;
+template class VersionNeedSection<ELF32BE>;
+template class VersionNeedSection<ELF64LE>;
+template class VersionNeedSection<ELF64BE>;
+
 template class BuildIdSection<ELF32LE>;
 template class BuildIdSection<ELF32BE>;
 template class BuildIdSection<ELF64LE>;

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=267775&r1=267774&r2=267775&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Wed Apr 27 15:22:31 2016
@@ -33,6 +33,8 @@ template <class ELFT> class MergeInputSe
 template <class ELFT> class MipsReginfoInputSection;
 template <class ELFT> class OutputSection;
 template <class ELFT> class ObjectFile;
+template <class ELFT> class SharedFile;
+template <class ELFT> class SharedSymbol;
 template <class ELFT> class DefinedRegular;
 
 template <class ELFT>
@@ -222,6 +224,49 @@ private:
   std::vector<std::pair<SymbolBody *, size_t>> Symbols;
 };
 
+// For more information about .gnu.version and .gnu.version_r see:
+// https://www.akkadia.org/drepper/symbol-versioning
+
+// The .gnu.version section specifies the required version of each symbol in the
+// dynamic symbol table. It contains one Elf_Versym for each dynamic symbol
+// table entry. An Elf_Versym is just a 16-bit integer that refers to a version
+// identifier defined in the .gnu.version_r section.
+template <class ELFT>
+class VersionTableSection final : public OutputSectionBase<ELFT> {
+  typedef typename ELFT::Versym Elf_Versym;
+
+public:
+  VersionTableSection();
+  void finalize() override;
+  void writeTo(uint8_t *Buf) override;
+};
+
+// The .gnu.version_r section defines the version identifiers used by
+// .gnu.version. It contains a linked list of Elf_Verneed data structures. Each
+// Elf_Verneed specifies the version requirements for a single DSO, and contains
+// a reference to a linked list of Elf_Vernaux data structures which define the
+// mapping from version identifiers to version names.
+template <class ELFT>
+class VersionNeedSection final : public OutputSectionBase<ELFT> {
+  typedef typename ELFT::Verneed Elf_Verneed;
+  typedef typename ELFT::Vernaux Elf_Vernaux;
+
+  // A vector of shared files that need Elf_Verneed data structures and the
+  // string table offsets of their sonames.
+  std::vector<std::pair<SharedFile<ELFT> *, size_t>> Needed;
+
+  // The next available version identifier. Identifiers start at 2 because 0 and
+  // 1 are reserved.
+  unsigned NextIndex = 2;
+
+public:
+  VersionNeedSection();
+  void addSymbol(SharedSymbol<ELFT> *SS);
+  void finalize() override;
+  void writeTo(uint8_t *Buf) override;
+  size_t getNeedNum() const { return Needed.size(); }
+};
+
 template <class ELFT>
 class RelocationSection final : public OutputSectionBase<ELFT> {
   typedef typename ELFT::Rel Elf_Rel;
@@ -562,6 +607,8 @@ template <class ELFT> struct Out {
   static StringTableSection<ELFT> *StrTab;
   static SymbolTableSection<ELFT> *DynSymTab;
   static SymbolTableSection<ELFT> *SymTab;
+  static VersionTableSection<ELFT> *VerSym;
+  static VersionNeedSection<ELFT> *VerNeed;
   static Elf_Phdr *TlsPhdr;
   static OutputSectionBase<ELFT> *ElfHeader;
   static OutputSectionBase<ELFT> *ProgramHeaders;
@@ -587,6 +634,8 @@ template <class ELFT> StringTableSection
 template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::StrTab;
 template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::DynSymTab;
 template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::SymTab;
+template <class ELFT> VersionTableSection<ELFT> *Out<ELFT>::VerSym;
+template <class ELFT> VersionNeedSection<ELFT> *Out<ELFT>::VerNeed;
 template <class ELFT> typename ELFT::Phdr *Out<ELFT>::TlsPhdr;
 template <class ELFT> OutputSectionBase<ELFT> *Out<ELFT>::ElfHeader;
 template <class ELFT> OutputSectionBase<ELFT> *Out<ELFT>::ProgramHeaders;

Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=267775&r1=267774&r2=267775&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Wed Apr 27 15:22:31 2016
@@ -324,6 +324,7 @@ public:
 
 template <class ELFT> class SharedSymbol : public Defined {
   typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::Verdef Elf_Verdef;
   typedef typename ELFT::uint uintX_t;
 
 public:
@@ -331,10 +332,11 @@ public:
     return S->kind() == SymbolBody::SharedKind;
   }
 
-  SharedSymbol(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym)
+  SharedSymbol(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym,
+               const Elf_Verdef *Verdef)
       : Defined(SymbolBody::SharedKind, Name, Sym.getBinding(), Sym.st_other,
                 Sym.getType()),
-        File(F), Sym(Sym) {
+        File(F), Sym(Sym), Verdef(Verdef) {
     // IFuncs defined in DSOs are treated as functions by the static linker.
     if (isGnuIFunc())
       Type = llvm::ELF::STT_FUNC;
@@ -343,6 +345,14 @@ public:
   SharedFile<ELFT> *File;
   const Elf_Sym &Sym;
 
+  // This field is initially a pointer to the symbol's version definition. As
+  // symbols are added to the version table, this field is replaced with the
+  // version identifier to be stored in .gnu.version in the output file.
+  union {
+    const Elf_Verdef *Verdef;
+    uint16_t VersionId;
+  };
+
   // OffsetInBss is significant only when needsCopy() is true.
   uintX_t OffsetInBss = 0;
 

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=267775&r1=267774&r2=267775&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Wed Apr 27 15:22:31 2016
@@ -132,6 +132,8 @@ template <class ELFT> void elf::writeRes
   StringTableSection<ELFT> DynStrTab(".dynstr", true);
   StringTableSection<ELFT> ShStrTab(".shstrtab", false);
   SymbolTableSection<ELFT> DynSymTab(*Symtab, DynStrTab);
+  VersionTableSection<ELFT> VerSym;
+  VersionNeedSection<ELFT> VerNeed;
 
   OutputSectionBase<ELFT> ElfHeader("", 0, SHF_ALLOC);
   ElfHeader.setSize(sizeof(Elf_Ehdr));
@@ -195,6 +197,8 @@ template <class ELFT> void elf::writeRes
   Out<ELFT>::ShStrTab = &ShStrTab;
   Out<ELFT>::StrTab = StrTab.get();
   Out<ELFT>::SymTab = SymTabSec.get();
+  Out<ELFT>::VerSym = &VerSym;
+  Out<ELFT>::VerNeed = &VerNeed;
   Out<ELFT>::Bss = nullptr;
   Out<ELFT>::MipsRldMap = MipsRldMap.get();
   Out<ELFT>::Opd = nullptr;
@@ -1367,8 +1371,11 @@ template <class ELFT> void Writer<ELFT>:
     if (Out<ELFT>::SymTab)
       Out<ELFT>::SymTab->addSymbol(Body);
 
-    if (isOutputDynamic() && S->includeInDynsym())
+    if (isOutputDynamic() && S->includeInDynsym()) {
       Out<ELFT>::DynSymTab->addSymbol(Body);
+      if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(Body))
+        Out<ELFT>::VerNeed->addSymbol(SS);
+    }
   }
 
   // Do not proceed if there was an undefined symbol.
@@ -1436,6 +1443,10 @@ template <class ELFT> void Writer<ELFT>:
   Add(Out<ELFT>::StrTab);
   if (isOutputDynamic()) {
     Add(Out<ELFT>::DynSymTab);
+    if (Out<ELFT>::VerNeed->getNeedNum() != 0) {
+      Add(Out<ELFT>::VerSym);
+      Add(Out<ELFT>::VerNeed);
+    }
     Add(Out<ELFT>::GnuHashTab);
     Add(Out<ELFT>::HashTab);
     Add(Out<ELFT>::Dynamic);

Added: lld/trunk/test/ELF/Inputs/verneed.so.sh
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/verneed.so.sh?rev=267775&view=auto
==============================================================================
--- lld/trunk/test/ELF/Inputs/verneed.so.sh (added)
+++ lld/trunk/test/ELF/Inputs/verneed.so.sh Wed Apr 27 15:22:31 2016
@@ -0,0 +1,58 @@
+#!/bin/sh -eu
+
+# This script was used to produce the verneed{1,2}.so files.
+
+tmp=$(mktemp -d)
+
+echo "v1 {}; v2 {}; v3 {}; { local: *; };" > $tmp/verneed.script
+
+cat > $tmp/verneed1.s <<eof
+.globl f1_v1
+f1_v1:
+ret
+
+.globl f1_v2
+f1_v2:
+ret
+
+.globl f1_v3
+f1_v3:
+ret
+
+.symver f1_v1, f1 at v1
+.symver f1_v2, f1 at v2
+.symver f1_v3, f1@@v3
+
+.globl f2_v1
+f2_v1:
+ret
+
+.globl f2_v2
+f2_v2:
+ret
+
+.symver f2_v1, f2 at v1
+.symver f2_v2, f2@@v2
+
+.globl f3_v1
+f3_v1:
+ret
+
+.symver f3_v1, f3 at v1
+eof
+
+as -o $tmp/verneed1.o $tmp/verneed1.s
+ld.gold -shared -o verneed1.so $tmp/verneed1.o --version-script $tmp/verneed.script -soname verneed1.so.0
+
+cat > $tmp/verneed2.s <<eof
+.globl g1_v1
+g1_v1:
+ret
+
+.symver g1_v1, g1@@v1
+eof
+
+as -o $tmp/verneed2.o $tmp/verneed2.s
+ld.gold -shared -o verneed2.so $tmp/verneed2.o --version-script $tmp/verneed.script -soname verneed2.so.0
+
+rm -rf $tmp

Propchange: lld/trunk/test/ELF/Inputs/verneed.so.sh
------------------------------------------------------------------------------
    svn:executable = *

Added: lld/trunk/test/ELF/Inputs/verneed1.so
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/verneed1.so?rev=267775&view=auto
==============================================================================
Binary files lld/trunk/test/ELF/Inputs/verneed1.so (added) and lld/trunk/test/ELF/Inputs/verneed1.so Wed Apr 27 15:22:31 2016 differ

Propchange: lld/trunk/test/ELF/Inputs/verneed1.so
------------------------------------------------------------------------------
    svn:executable = *

Added: lld/trunk/test/ELF/Inputs/verneed2.so
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/verneed2.so?rev=267775&view=auto
==============================================================================
Binary files lld/trunk/test/ELF/Inputs/verneed2.so (added) and lld/trunk/test/ELF/Inputs/verneed2.so Wed Apr 27 15:22:31 2016 differ

Propchange: lld/trunk/test/ELF/Inputs/verneed2.so
------------------------------------------------------------------------------
    svn:executable = *

Added: lld/trunk/test/ELF/verneed-local.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/verneed-local.s?rev=267775&view=auto
==============================================================================
--- lld/trunk/test/ELF/verneed-local.s (added)
+++ lld/trunk/test/ELF/verneed-local.s Wed Apr 27 15:22:31 2016
@@ -0,0 +1,8 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld %t.o %S/Inputs/verneed1.so -o %t 2>&1 | FileCheck %s
+
+# CHECK: undefined symbol: f3 in
+.globl _start
+_start:
+call f3

Added: lld/trunk/test/ELF/verneed.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/verneed.s?rev=267775&view=auto
==============================================================================
--- lld/trunk/test/ELF/verneed.s (added)
+++ lld/trunk/test/ELF/verneed.s Wed Apr 27 15:22:31 2016
@@ -0,0 +1,104 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o %S/Inputs/verneed1.so %S/Inputs/verneed2.so -o %t
+# RUN: llvm-readobj -sections -dyn-symbols -dynamic-table %t | FileCheck %s
+# RUN: llvm-objdump -s %t | FileCheck --check-prefix=CONTENTS %s
+
+# CHECK:        Index: 2
+# CHECK-NEXT:   Name: .gnu.version (9)
+# CHECK-NEXT:   Type: SHT_GNU_versym (0x6FFFFFFF)
+# CHECK-NEXT:   Flags [ (0x2)
+# CHECK-NEXT:     SHF_ALLOC (0x2)
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x10228
+# CHECK-NEXT:   Offset: 0x228
+# CHECK-NEXT:   Size: 8
+# CHECK-NEXT:   Link: 0
+# CHECK-NEXT:   Info: 0
+# CHECK-NEXT:   AddressAlignment: 0
+# CHECK-NEXT:   EntrySize: 2
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index: 3
+# CHECK-NEXT:   Name: .gnu.version_r (22)
+# CHECK-NEXT:   Type: SHT_GNU_verneed (0x6FFFFFFE)
+# CHECK-NEXT:   Flags [ (0x2)
+# CHECK-NEXT:     SHF_ALLOC (0x2)
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x10230
+# CHECK-NEXT:   Offset: 0x230
+# CHECK-NEXT:   Size: 80
+# CHECK-NEXT:   Link: 5
+# CHECK-NEXT:   Info: 2
+# CHECK-NEXT:   AddressAlignment: 0
+# CHECK-NEXT:   EntrySize: 0
+# CHECK-NEXT: }
+
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: @ (0)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local (0x0)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: f1 at v3 (1)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: f2 at v2 (21)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: g1 at v1 (27)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+# CHECK:      0x000000006FFFFFF0 VERSYM               0x10228
+# CHECK-NEXT: 0x000000006FFFFFFE VERNEED              0x10230
+# CHECK-NEXT: 0x000000006FFFFFFF VERNEEDNUM           2
+
+# CONTENTS:      Contents of section .gnu.version:
+# CONTENTS-NEXT:  10228 00000200 03000400
+# CONTENTS-NEXT: Contents of section .gnu.version_r:
+#                       vn_version
+#                           vn_cnt
+#                                vn_file  vn_aux   vn_next
+# CONTENTS-NEXT:  10230 01000200 04000000 20000000 10000000  ........ .......
+# CONTENTS-NEXT:  10240 01000100 1e000000 30000000 00000000  ........0.......
+#                       vna_hash vna_flags
+#                                    vna_other
+#                                         vna_name
+#                                                  vna_next
+# CONTENTS-NEXT:  10250 92070000 00000300 18000000 10000000  ................
+# CONTENTS-NEXT:  10260 93070000 00000200 12000000 00000000  ................
+# CONTENTS-NEXT:  10270 91070000 00000400 2c000000 00000000  ........,.......
+# CONTENTS:      Contents of section .dynstr:
+# CONTENTS-NEXT:  102a8 00663100 7665726e 65656431 2e736f2e  .f1.verneed1.so.
+# CONTENTS-NEXT:  102b8 30007633 00663200 76320067 31007665  0.v3.f2.v2.g1.ve
+# CONTENTS-NEXT:  102c8 726e6565 64322e73 6f2e3000 763100    rneed2.so.0.v1.
+
+.globl _start
+_start:
+call f1
+call f2
+call g1




More information about the llvm-commits mailing list