[lld] r246797 - Start adding support for shared libraries.

Rafael Espindola via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 3 13:03:54 PDT 2015


Author: rafael
Date: Thu Sep  3 15:03:54 2015
New Revision: 246797

URL: http://llvm.org/viewvc/llvm-project?rev=246797&view=rev
Log:
Start adding support for shared libraries.

This just adds the types and enough support to detect incompatibilities among
shared libraries and object files.

Added:
    lld/trunk/test/elf2/Inputs/i686-simple-library.so   (with props)
Modified:
    lld/trunk/ELF/Driver.cpp
    lld/trunk/ELF/InputFiles.cpp
    lld/trunk/ELF/InputFiles.h
    lld/trunk/ELF/SymbolTable.cpp
    lld/trunk/ELF/SymbolTable.h
    lld/trunk/ELF/Writer.cpp
    lld/trunk/test/elf2/incompatible.s

Modified: lld/trunk/ELF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=246797&r1=246796&r2=246797&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.cpp (original)
+++ lld/trunk/ELF/Driver.cpp Thu Sep  3 15:03:54 2015
@@ -14,6 +14,7 @@
 #include "SymbolTable.h"
 #include "Writer.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/FileSystem.h"
 
 using namespace llvm;
 
@@ -44,21 +45,33 @@ MemoryBufferRef LinkerDriver::openFile(S
   return MBRef;
 }
 
+template <class ELFT>
+static std::unique_ptr<InputFile> createFile(MemoryBufferRef MB,
+                                             bool IsShared) {
+  if (IsShared)
+    return make_unique<SharedFile<ELFT>>(MB);
+  return make_unique<ObjectFile<ELFT>>(MB);
+}
+
 static std::unique_ptr<InputFile> createFile(MemoryBufferRef MB) {
+  using namespace llvm::sys::fs;
+  file_magic Magic = identify_magic(MB.getBuffer());
+
   std::pair<unsigned char, unsigned char> Type =
       object::getElfArchType(MB.getBuffer());
   if (Type.second != ELF::ELFDATA2LSB && Type.second != ELF::ELFDATA2MSB)
     error("Invalid data encoding");
 
+  bool IsShared = Magic == file_magic::elf_shared_object;
   if (Type.first == ELF::ELFCLASS32) {
     if (Type.second == ELF::ELFDATA2LSB)
-      return make_unique<ObjectFile<object::ELF32LE>>(MB);
-    return make_unique<ObjectFile<object::ELF32BE>>(MB);
+      return createFile<object::ELF32LE>(MB, IsShared);
+    return createFile<object::ELF32BE>(MB, IsShared);
   }
   if (Type.first == ELF::ELFCLASS64) {
     if (Type.second == ELF::ELFDATA2LSB)
-      return make_unique<ObjectFile<object::ELF64LE>>(MB);
-    return make_unique<ObjectFile<object::ELF64BE>>(MB);
+      return createFile<object::ELF64LE>(MB, IsShared);
+    return createFile<object::ELF64BE>(MB, IsShared);
   }
   error("Invalid file class");
 }
@@ -98,8 +111,8 @@ void LinkerDriver::link(ArrayRef<const c
   Symtab.reportRemainingUndefines();
 
   // Write the result.
-  ObjectFileBase &FirstObj = *Symtab.getFirstObject();
-  switch (FirstObj.getELFKind()) {
+  const ELFFileBase *FirstObj = Symtab.getFirstELF();
+  switch (FirstObj->getELFKind()) {
   case ELF32LEKind:
     writeResult<object::ELF32LE>(&Symtab);
     return;

Modified: lld/trunk/ELF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=246797&r1=246796&r2=246797&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.cpp (original)
+++ lld/trunk/ELF/InputFiles.cpp Thu Sep  3 15:03:54 2015
@@ -14,23 +14,46 @@
 #include "llvm/ADT/STLExtras.h"
 
 using namespace llvm::ELF;
+using namespace llvm::object;
 
 using namespace lld;
 using namespace lld::elf2;
 
-template <class ELFT>
-bool ObjectFile<ELFT>::isCompatibleWith(const ObjectFileBase &Other) const {
-  if (getELFKind() != Other.getELFKind())
-    return false;
-  return getObj()->getHeader()->e_machine ==
-         cast<ObjectFile<ELFT>>(Other).getObj()->getHeader()->e_machine;
+template <class ELFT> static uint16_t getEMachine(const ELFFileBase &B) {
+  bool IsShared = isa<SharedFileBase>(B);
+  if (IsShared)
+    return cast<SharedFile<ELFT>>(B).getEMachine();
+  return cast<ObjectFile<ELFT>>(B).getEMachine();
+}
+
+static uint16_t getEMachine(const ELFFileBase &B) {
+  ELFKind K = B.getELFKind();
+  switch (K) {
+  case ELF32BEKind:
+    return getEMachine<ELF32BE>(B);
+  case ELF32LEKind:
+    return getEMachine<ELF32LE>(B);
+  case ELF64BEKind:
+    return getEMachine<ELF64BE>(B);
+  case ELF64LEKind:
+    return getEMachine<ELF64LE>(B);
+  }
 }
 
-template <class ELFT> void elf2::ObjectFile<ELFT>::parse() {
+bool ELFFileBase::isCompatibleWith(const ELFFileBase &Other) const {
+  return getELFKind() == Other.getELFKind() &&
+         getEMachine(*this) == getEMachine(Other);
+}
+
+template <class ELFT> void ELFData<ELFT>::openELF(MemoryBufferRef MB) {
   // Parse a memory buffer as a ELF file.
   std::error_code EC;
   ELFObj = llvm::make_unique<ELFFile<ELFT>>(MB.getBuffer(), EC);
   error(EC);
+}
+
+template <class ELFT> void elf2::ObjectFile<ELFT>::parse() {
+  this->openELF(MB);
 
   // Read section and symbol tables.
   initializeChunks();
@@ -38,16 +61,17 @@ template <class ELFT> void elf2::ObjectF
 }
 
 template <class ELFT> void elf2::ObjectFile<ELFT>::initializeChunks() {
-  uint64_t Size = ELFObj->getNumSections();
+  uint64_t Size = this->ELFObj->getNumSections();
   Chunks.resize(Size);
   unsigned I = 0;
-  for (const Elf_Shdr &Sec : ELFObj->sections()) {
+  for (const Elf_Shdr &Sec : this->ELFObj->sections()) {
     switch (Sec.sh_type) {
     case SHT_SYMTAB:
       Symtab = &Sec;
       break;
     case SHT_SYMTAB_SHNDX: {
-      ErrorOr<ArrayRef<Elf_Word>> ErrorOrTable = ELFObj->getSHNDXTable(Sec);
+      ErrorOr<ArrayRef<Elf_Word>> ErrorOrTable =
+          this->ELFObj->getSHNDXTable(Sec);
       error(ErrorOrTable);
       SymtabSHNDX = *ErrorOrTable;
       break;
@@ -76,11 +100,11 @@ template <class ELFT> void elf2::ObjectF
 
 template <class ELFT> void elf2::ObjectFile<ELFT>::initializeSymbols() {
   ErrorOr<StringRef> StringTableOrErr =
-      ELFObj->getStringTableForSymtab(*Symtab);
+      this->ELFObj->getStringTableForSymtab(*Symtab);
   error(StringTableOrErr.getError());
   StringRef StringTable = *StringTableOrErr;
 
-  Elf_Sym_Range Syms = ELFObj->symbols(Symtab);
+  Elf_Sym_Range Syms = this->ELFObj->symbols(Symtab);
   uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
   uint32_t FirstNonLocal = Symtab->sh_info;
   if (FirstNonLocal > NumSymbols)
@@ -107,7 +131,8 @@ SymbolBody *elf2::ObjectFile<ELFT>::crea
   case SHN_COMMON:
     return new (Alloc) DefinedCommon<ELFT>(Name, *Sym);
   case SHN_XINDEX:
-    SecIndex = ELFObj->getExtendedSymbolTableIndex(Sym, Symtab, SymtabSHNDX);
+    SecIndex =
+        this->ELFObj->getExtendedSymbolTableIndex(Sym, Symtab, SymtabSHNDX);
     break;
   }
 
@@ -124,11 +149,18 @@ SymbolBody *elf2::ObjectFile<ELFT>::crea
   }
 }
 
+template <class ELFT> void SharedFile<ELFT>::parse() { this->openELF(MB); }
+
 namespace lld {
 namespace elf2 {
 template class elf2::ObjectFile<llvm::object::ELF32LE>;
 template class elf2::ObjectFile<llvm::object::ELF32BE>;
 template class elf2::ObjectFile<llvm::object::ELF64LE>;
 template class elf2::ObjectFile<llvm::object::ELF64BE>;
+
+template class elf2::SharedFile<llvm::object::ELF32LE>;
+template class elf2::SharedFile<llvm::object::ELF32BE>;
+template class elf2::SharedFile<llvm::object::ELF64LE>;
+template class elf2::SharedFile<llvm::object::ELF64BE>;
 }
 }

Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=246797&r1=246796&r2=246797&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Thu Sep  3 15:03:54 2015
@@ -23,7 +23,7 @@ class SymbolBody;
 // The root class of input files.
 class InputFile {
 public:
-  enum Kind { ObjectKind };
+  enum Kind { ObjectKind, SharedKind };
   Kind kind() const { return FileKind; }
   virtual ~InputFile() {}
 
@@ -42,59 +42,79 @@ private:
 
 enum ELFKind { ELF32LEKind, ELF32BEKind, ELF64LEKind, ELF64BEKind };
 
+class ELFFileBase : public InputFile {
+public:
+  explicit ELFFileBase(Kind K, ELFKind EKind, MemoryBufferRef M)
+      : InputFile(K, M), EKind(EKind) {}
+  static bool classof(const InputFile *F) {
+    Kind K = F->kind();
+    return K == ObjectKind || K == SharedKind;
+  }
+
+  bool isCompatibleWith(const ELFFileBase &Other) const;
+  ELFKind getELFKind() const { return EKind; }
+
+protected:
+  const ELFKind EKind;
+};
+
 // .o file.
-class ObjectFileBase : public InputFile {
+class ObjectFileBase : public ELFFileBase {
 public:
   explicit ObjectFileBase(ELFKind EKind, MemoryBufferRef M)
-      : InputFile(ObjectKind, M), EKind(EKind) {}
+      : ELFFileBase(ObjectKind, EKind, M) {}
   static bool classof(const InputFile *F) { return F->kind() == ObjectKind; }
 
   ArrayRef<SymbolBody *> getSymbols() { return SymbolBodies; }
 
-  virtual bool isCompatibleWith(const ObjectFileBase &Other) const = 0;
-
-  ELFKind getELFKind() const { return EKind; }
-
 protected:
   // List of all symbols referenced or defined by this file.
   std::vector<SymbolBody *> SymbolBodies;
 
   llvm::BumpPtrAllocator Alloc;
-  const ELFKind EKind;
 };
 
-template <class ELFT> class ObjectFile : public ObjectFileBase {
+template <class ELFT> static ELFKind getStaticELFKind() {
+  if (!ELFT::Is64Bits) {
+    if (ELFT::TargetEndianness == llvm::support::little)
+      return ELF32LEKind;
+    return ELF32BEKind;
+  }
+  if (ELFT::TargetEndianness == llvm::support::little)
+    return ELF64LEKind;
+  return ELF64BEKind;
+}
+
+template <class ELFT> class ELFData {
+public:
+  llvm::object::ELFFile<ELFT> *getObj() const { return ELFObj.get(); }
+
+  uint16_t getEMachine() const { return getObj()->getHeader()->e_machine; }
+
+protected:
+  std::unique_ptr<llvm::object::ELFFile<ELFT>> ELFObj;
+
+  void openELF(MemoryBufferRef MB);
+};
+
+template <class ELFT>
+class ObjectFile : public ObjectFileBase, public ELFData<ELFT> {
   typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
   typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
   typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
   typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word;
 
 public:
-  bool isCompatibleWith(const ObjectFileBase &Other) const override;
-
-  static ELFKind getStaticELFKind() {
-    if (!ELFT::Is64Bits) {
-      if (ELFT::TargetEndianness == llvm::support::little)
-        return ELF32LEKind;
-      return ELF32BEKind;
-    }
-    if (ELFT::TargetEndianness == llvm::support::little)
-      return ELF64LEKind;
-    return ELF64BEKind;
-  }
 
   static bool classof(const InputFile *F) {
     return F->kind() == ObjectKind &&
-           cast<ObjectFileBase>(F)->getELFKind() == getStaticELFKind();
+           cast<ELFFileBase>(F)->getELFKind() == getStaticELFKind<ELFT>();
   }
 
   explicit ObjectFile(MemoryBufferRef M)
-      : ObjectFileBase(getStaticELFKind(), M) {}
+      : ObjectFileBase(getStaticELFKind<ELFT>(), M) {}
   void parse() override;
 
-  // Returns the underying ELF file.
-  llvm::object::ELFFile<ELFT> *getObj() const { return ELFObj.get(); }
-
   ArrayRef<SectionChunk<ELFT> *> getChunks() { return Chunks; }
 
   SymbolBody *getSymbolBody(uint32_t SymbolIndex) {
@@ -110,8 +130,6 @@ private:
 
   SymbolBody *createSymbolBody(StringRef StringTable, const Elf_Sym *Sym);
 
-  std::unique_ptr<llvm::object::ELFFile<ELFT>> ELFObj;
-
   // List of all chunks defined by this file.
   std::vector<SectionChunk<ELFT> *> Chunks;
 
@@ -119,6 +137,28 @@ private:
   ArrayRef<Elf_Word> SymtabSHNDX;
 };
 
+// .so file.
+class SharedFileBase : public ELFFileBase {
+public:
+  explicit SharedFileBase(ELFKind EKind, MemoryBufferRef M)
+      : ELFFileBase(SharedKind, EKind, M) {}
+  static bool classof(const InputFile *F) { return F->kind() == SharedKind; }
+};
+
+template <class ELFT>
+class SharedFile : public SharedFileBase, public ELFData<ELFT> {
+public:
+  static bool classof(const InputFile *F) {
+    return F->kind() == SharedKind &&
+           cast<ELFFileBase>(F)->getELFKind() == getStaticELFKind<ELFT>();
+  }
+
+  explicit SharedFile(MemoryBufferRef M)
+      : SharedFileBase(getStaticELFKind<ELFT>(), M) {}
+
+  void parse() override;
+};
+
 } // namespace elf2
 } // namespace lld
 

Modified: lld/trunk/ELF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.cpp?rev=246797&r1=246796&r2=246797&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.cpp (original)
+++ lld/trunk/ELF/SymbolTable.cpp Thu Sep  3 15:03:54 2015
@@ -23,8 +23,8 @@ SymbolTable::SymbolTable() {
 void SymbolTable::addFile(std::unique_ptr<InputFile> File) {
   File->parse();
   InputFile *FileP = File.release();
-  auto *P = cast<ObjectFileBase>(FileP);
-  addObject(P);
+  auto *P = cast<ELFFileBase>(FileP);
+  addELFFile(P);
 }
 
 template <class ELFT> void SymbolTable::init() {
@@ -32,8 +32,8 @@ template <class ELFT> void SymbolTable::
                     Undefined<ELFT>("_start", Undefined<ELFT>::Synthetic));
 }
 
-void SymbolTable::addObject(ObjectFileBase *File) {
-  if (const ObjectFileBase *Old = getFirstObject()) {
+void SymbolTable::addELFFile(ELFFileBase *File) {
+  if (const ELFFileBase *Old = getFirstELF()) {
     if (!Old->isCompatibleWith(*File))
       error(Twine(Old->getName() + " is incompatible with " + File->getName()));
   } else {
@@ -53,23 +53,28 @@ void SymbolTable::addObject(ObjectFileBa
     }
   }
 
-  ObjectFiles.emplace_back(File);
-  for (SymbolBody *Body : File->getSymbols()) {
-    switch (File->getELFKind()) {
-    case ELF32LEKind:
-      resolve<ELF32LE>(Body);
-      break;
-    case ELF32BEKind:
-      resolve<ELF32BE>(Body);
-      break;
-    case ELF64LEKind:
-      resolve<ELF64LE>(Body);
-      break;
-    case ELF64BEKind:
-      resolve<ELF64BE>(Body);
-      break;
+  if (auto *O = dyn_cast<ObjectFileBase>(File)) {
+    ObjectFiles.emplace_back(O);
+    for (SymbolBody *Body : O->getSymbols()) {
+      switch (File->getELFKind()) {
+      case ELF32LEKind:
+        resolve<ELF32LE>(Body);
+        break;
+      case ELF32BEKind:
+        resolve<ELF32BE>(Body);
+        break;
+      case ELF64LEKind:
+        resolve<ELF64LE>(Body);
+        break;
+      case ELF64BEKind:
+        resolve<ELF64BE>(Body);
+        break;
+      }
     }
   }
+
+  if (auto *S = dyn_cast<SharedFileBase>(File))
+    SharedFiles.emplace_back(S);
 }
 
 void SymbolTable::reportRemainingUndefines() {

Modified: lld/trunk/ELF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.h?rev=246797&r1=246796&r2=246797&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.h (original)
+++ lld/trunk/ELF/SymbolTable.h Thu Sep  3 15:03:54 2015
@@ -34,9 +34,11 @@ public:
 
   void addFile(std::unique_ptr<InputFile> File);
 
-  ObjectFileBase *getFirstObject() const {
+  const ELFFileBase *getFirstELF() const {
     if (!ObjectFiles.empty())
       return ObjectFiles[0].get();
+    if (!SharedFiles.empty())
+      return SharedFiles[0].get();
     return nullptr;
   }
 
@@ -52,7 +54,7 @@ public:
   }
 
 private:
-  void addObject(ObjectFileBase *File);
+  void addELFFile(ELFFileBase *File);
 
   template <class ELFT> void init();
   template <class ELFT> void resolve(SymbolBody *Body);
@@ -62,6 +64,8 @@ private:
 
   // The writer needs to infer the machine type from the object files.
   std::vector<std::unique_ptr<ObjectFileBase>> ObjectFiles;
+
+  std::vector<std::unique_ptr<SharedFileBase>> SharedFiles;
 };
 
 } // namespace elf2

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=246797&r1=246796&r2=246797&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Thu Sep  3 15:03:54 2015
@@ -543,8 +543,8 @@ template <class ELFT> void Writer<ELFT>:
 
   EHdr->e_type = ET_EXEC;
   const SymbolTable &Symtab = SymTable.getSymTable();
-  auto &FirstObj = cast<ObjectFile<ELFT>>(*Symtab.getFirstObject());
-  EHdr->e_machine = FirstObj.getObj()->getHeader()->e_machine;
+  auto &FirstObj = cast<ObjectFile<ELFT>>(*Symtab.getFirstELF());
+  EHdr->e_machine = FirstObj.getEMachine();
   EHdr->e_version = EV_CURRENT;
   EHdr->e_entry = 0x401000;
   EHdr->e_phoff = sizeof(Elf_Ehdr_Impl<ELFT>);

Added: lld/trunk/test/elf2/Inputs/i686-simple-library.so
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/Inputs/i686-simple-library.so?rev=246797&view=auto
==============================================================================
Binary files lld/trunk/test/elf2/Inputs/i686-simple-library.so (added) and lld/trunk/test/elf2/Inputs/i686-simple-library.so Thu Sep  3 15:03:54 2015 differ

Propchange: lld/trunk/test/elf2/Inputs/i686-simple-library.so
------------------------------------------------------------------------------
    svn:executable = *

Modified: lld/trunk/test/elf2/incompatible.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/incompatible.s?rev=246797&r1=246796&r2=246797&view=diff
==============================================================================
--- lld/trunk/test/elf2/incompatible.s (original)
+++ lld/trunk/test/elf2/incompatible.s Thu Sep  3 15:03:54 2015
@@ -10,4 +10,17 @@
 // RUN:   FileCheck --check-prefix=B-AND-C %s
 // B-AND-C: b.o is incompatible with {{.*}}c.o
 
+// FIMME: create the .so ourselves once we are able to
+// RUN: not lld -flavor gnu2 %ta.o %p/Inputs/i686-simple-library.so -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=A-AND-SO %s
+// A-AND-SO: a.o is incompatible with {{.*}}/Inputs/i686-simple-library.so
+
+// RUN: not lld -flavor gnu2 %tc.o %p/Inputs/i686-simple-library.so -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=C-AND-SO %s
+// C-AND-SO: c.o is incompatible with {{.*}}/Inputs/i686-simple-library.so
+
+// RUN: not lld -flavor gnu2 %p/Inputs/i686-simple-library.so %tc.o -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=SO-AND-C %s
+// SO-AND-C: /Inputs/i686-simple-library.so is incompatible with {{.*}}c.o
+
 // REQUIRES: x86,arm




More information about the llvm-commits mailing list