[ELF] Add COPY relocations.
authorMichael J. Spencer <bigcheesegs@gmail.com>
Thu, 26 Sep 2013 22:09:16 +0000 (22:09 +0000)
committerMichael J. Spencer <bigcheesegs@gmail.com>
Thu, 26 Sep 2013 22:09:16 +0000 (22:09 +0000)
llvm-svn: 191467

lld/lib/ReaderWriter/ELF/Atoms.h
lld/lib/ReaderWriter/ELF/SectionChunks.h
lld/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp
lld/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h
lld/test/elf/Inputs/libundef.so [new file with mode: 0644]
lld/test/elf/Inputs/undef-from-main-so.c [new file with mode: 0644]
lld/test/elf/Inputs/undef-from-main.c [new file with mode: 0644]
lld/test/elf/Inputs/undef.o [new file with mode: 0644]
lld/test/elf/dynamic.test
lld/test/elf/undef-from-main-dso.test [moved from lld/test/missing/undef-from-main-dso.test with 86% similarity]

index de27292..0949279 100644 (file)
@@ -796,6 +796,37 @@ private:
   const Elf_Sym *_symbol;
 };
 
+/// \brief Atom which represents an object for which a COPY relocation will be
+///   generated.
+class ObjectAtom : public SimpleDefinedAtom {
+public:
+  ObjectAtom(const File &f) : SimpleDefinedAtom(f) {}
+
+  virtual Scope scope() const { return scopeGlobal; }
+
+  virtual SectionChoice sectionChoice() const { return sectionBasedOnContent; }
+
+  virtual ContentType contentType() const { return typeZeroFill; }
+
+  virtual uint64_t size() const { return _size; }
+
+  virtual ContentPermissions permissions() const { return permRW_; }
+
+  virtual ArrayRef<uint8_t> rawContent() const {
+    return ArrayRef<uint8_t>();
+  }
+
+  virtual Alignment alignment() const {
+    // The alignment should be 8 byte aligned
+    return Alignment(3);
+  }
+
+  virtual StringRef name() const { return _name; }
+
+  std::string _name;
+  uint64_t _size;
+};
+
 class GOTAtom : public SimpleDefinedAtom {
   StringRef _section;
 
index d2e0826..ac194bf 100644 (file)
@@ -770,7 +770,11 @@ template <class ELFT>
 void SymbolTable<ELFT>::addSharedLibAtom(Elf_Sym &sym,
                                          const SharedLibraryAtom *aa) {
   unsigned char binding = 0, type = 0;
-  type = llvm::ELF::STT_FUNC;
+  if (aa->type() == SharedLibraryAtom::Type::Data) {
+    type = llvm::ELF::STT_OBJECT;
+    sym.st_size = aa->size();
+  } else
+    type = llvm::ELF::STT_FUNC;
   sym.st_shndx = llvm::ELF::SHN_UNDEF;
   binding = llvm::ELF::STB_GLOBAL;
   sym.setBindingAndType(binding, type);
index 6892706..2ef6f38 100644 (file)
@@ -89,6 +89,9 @@ template <class Derived> class GOTPLTPass : public Pass {
   /// \brief Handle a specific reference.
   void handleReference(const DefinedAtom &atom, const Reference &ref) {
     switch (ref.kind()) {
+    case R_X86_64_32S:
+      static_cast<Derived *>(this)->handle32S(ref);
+      break;
     case R_X86_64_PLT32:
       static_cast<Derived *>(this)->handlePLT32(ref);
       break;
@@ -245,6 +248,10 @@ public:
       got->setOrdinal(ordinal++);
       mf.addAtom(*got);
     }
+    for (auto obj : _objectVector) {
+      obj->setOrdinal(ordinal++);
+      mf.addAtom(*obj);
+    }
   }
 
 protected:
@@ -257,9 +264,13 @@ protected:
   /// \brief Map Atoms to their PLT entries.
   llvm::DenseMap<const Atom *, PLTAtom *> _pltMap;
 
+  /// \brief Map Atoms to their Object entries.
+  llvm::DenseMap<const Atom *, ObjectAtom *> _objectMap;
+
   /// \brief the list of GOT/PLT atoms
   std::vector<GOTAtom *> _gotVector;
   std::vector<PLTAtom *> _pltVector;
+  std::vector<ObjectAtom *> _objectVector;
 
   /// \brief GOT entry that is always 0. Used for undefined weaks.
   GOTAtom *_null;
@@ -300,6 +311,11 @@ public:
   }
 
   ErrorOr<void> handlePC32(const Reference &ref) { return handleIFUNC(ref); }
+
+  ErrorOr<void> handle32S(const Reference &ref) {
+    // Do nothing.
+    return error_code::success();
+  }
 };
 
 class DynamicGOTPLTPass LLVM_FINAL : public GOTPLTPass<DynamicGOTPLTPass> {
@@ -349,6 +365,29 @@ public:
     return pa;
   }
 
+  const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a) {
+    auto obj = _objectMap.find(a);
+    if (obj != _objectMap.end())
+      return obj->second;
+
+    auto oa = new (_file._alloc) ObjectAtom(_file);
+    oa->addReference(R_X86_64_COPY, 0, a, 0);
+
+    oa->_name = a->name();
+    oa->_size = a->size();
+
+    _objectMap[a] = oa;
+    _objectVector.push_back(oa);
+    return oa;
+  }
+
+  ErrorOr<void> handle32S(const Reference &ref) {
+    if (auto sla = dyn_cast_or_null<SharedLibraryAtom>(ref.target()))
+      if (sla->type() == SharedLibraryAtom::Type::Data)
+        const_cast<Reference &>(ref).setTarget(getObjectEntry(sla));
+    return error_code::success();
+  }
+
   ErrorOr<void> handlePLT32(const Reference &ref) {
     // Turn this into a PC32 to the PLT entry.
     const_cast<Reference &>(ref).setKind(R_X86_64_PC32);
@@ -363,8 +402,14 @@ public:
   }
 
   ErrorOr<void> handlePC32(const Reference &ref) {
-    if (ref.target() && isa<SharedLibraryAtom>(ref.target()))
-      return handlePLT32(ref);
+    if (!ref.target())
+      return error_code::success();
+    if (auto sla = dyn_cast<SharedLibraryAtom>(ref.target())) {
+      if (sla->type() == SharedLibraryAtom::Type::Code)
+        return handlePLT32(ref);
+      else
+        return handleGOTPCREL(ref);
+    }
     return handleIFUNC(ref);
   }
 
@@ -384,7 +429,7 @@ public:
     return got->second;
   }
 
-  void handleGOTPCREL(const Reference &ref) {
+  ErrorOr<void> handleGOTPCREL(const Reference &ref) {
     const_cast<Reference &>(ref).setKind(R_X86_64_PC32);
     if (isa<UndefinedAtom>(ref.target()))
       const_cast<Reference &>(ref).setTarget(getNullGOT());
@@ -392,6 +437,7 @@ public:
       const_cast<Reference &>(ref).setTarget(getGOT(da));
     else if (const auto sla = dyn_cast<const SharedLibraryAtom>(ref.target()))
       const_cast<Reference &>(ref).setTarget(getSharedGOT(sla));
+    return error_code::success();
   }
 };
 
index a639cb3..e33e40a 100644 (file)
@@ -46,6 +46,7 @@ public:
     switch (r.kind()) {
     case llvm::ELF::R_X86_64_RELATIVE:
     case llvm::ELF::R_X86_64_GLOB_DAT:
+    case llvm::ELF::R_X86_64_COPY:
       return true;
     default:
       return false;
diff --git a/lld/test/elf/Inputs/libundef.so b/lld/test/elf/Inputs/libundef.so
new file mode 100644 (file)
index 0000000..41f2a66
Binary files /dev/null and b/lld/test/elf/Inputs/libundef.so differ
diff --git a/lld/test/elf/Inputs/undef-from-main-so.c b/lld/test/elf/Inputs/undef-from-main-so.c
new file mode 100644 (file)
index 0000000..f1cb63d
--- /dev/null
@@ -0,0 +1 @@
+int x[2] = {1, 2};
diff --git a/lld/test/elf/Inputs/undef-from-main.c b/lld/test/elf/Inputs/undef-from-main.c
new file mode 100644 (file)
index 0000000..366d934
--- /dev/null
@@ -0,0 +1,5 @@
+extern int x[2];
+
+int main() {
+  x[0] = 2;
+}
diff --git a/lld/test/elf/Inputs/undef.o b/lld/test/elf/Inputs/undef.o
new file mode 100644 (file)
index 0000000..3c9b60c
Binary files /dev/null and b/lld/test/elf/Inputs/undef.o differ
index 0a1a7a6..f124a34 100644 (file)
@@ -57,7 +57,7 @@ CHECK:          Name: i
 CHECK-NEXT:     Value: 0
 CHECK-NEXT:     Size:
 CHECK-NEXT:     Binding: Global
-CHECK-NEXT:     Type: Function
+CHECK-NEXT:     Type: Object
 CHECK:        }
 
 CHECK: DynamicSection [ (15 entries)
similarity index 86%
rename from lld/test/missing/undef-from-main-dso.test
rename to lld/test/elf/undef-from-main-dso.test
index 5683739..c1e7962 100644 (file)
@@ -1,8 +1,6 @@
-RUN: lld -flavor gnu -e main -o %t -L%p/Inputs -ltest %p/Inputs/undef-from-main.o
+RUN: lld -flavor gnu -e main -o %t -L%p/Inputs -lundef %p/Inputs/undef.o
 RUN: llvm-readobj -relocations -symbols %t | FileCheck %s
 
-XFAIL: *
-
 # DSO source code:
 # int x[2] = { 1, 2 };
 #