[llvm-commits] [PATCH] [lld][ELF] Add very basic support for IFUNC.

Michael Spencer bigcheesegs at gmail.com
Wed Jan 23 18:07:07 PST 2013


Hi kledzik, shankarke, khemant,

This currently just generates the plt and got entries with correct relocations. The writer will not know what to do with the relocations. Or the got and plt entries for that matter.

This clearly needs to be in separate files, but I believe Shankar has a change that does the initial work for this.

http://llvm-reviews.chandlerc.com/D324

Files:
  lib/ReaderWriter/ELF/ELFTargetInfo.cpp
  test/elf/Inputs/ifunc.cpp
  test/elf/Inputs/ifunc.cpp.x86-64
  test/elf/ifunc.test

Index: lib/ReaderWriter/ELF/ELFTargetInfo.cpp
===================================================================
--- lib/ReaderWriter/ELF/ELFTargetInfo.cpp
+++ lib/ReaderWriter/ELF/ELFTargetInfo.cpp
@@ -9,9 +9,15 @@
 
 #include "lld/ReaderWriter/ELFTargetInfo.h"
 
+#include "lld/Core/File.h"
 #include "lld/Core/LinkerOptions.h"
+#include "lld/Core/Pass.h"
+#include "lld/Core/PassManager.h"
+#include "lld/Core/Simple.h"
 
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/Triple.h"
+#include "llvm/Support/Allocator.h"
 #include "llvm/Support/ELF.h"
 
 namespace lld {
@@ -56,6 +62,112 @@
   virtual uint64_t getPageSize() const { return 0x1000; }
 };
 
+class GOTAtom : public SimpleDefinedAtom {
+  static const uint8_t _defaultContent[8];
+
+public:
+  GOTAtom(const File &f, const DefinedAtom *target) : SimpleDefinedAtom(f) {
+    if (target->contentType() == DefinedAtom::typeResolver)
+      addReference(llvm::ELF::R_X86_64_IRELATIVE, 0, target, 0);
+  }
+
+  virtual ContentType contentType() const {
+    return DefinedAtom::typeGOT;
+  }
+
+  virtual uint64_t size() const {
+    return rawContent().size();
+  }
+
+  virtual ContentPermissions permissions() const {
+    return DefinedAtom::permRW_;
+  }
+
+  virtual ArrayRef<uint8_t> rawContent() const {
+    return ArrayRef<uint8_t>(_defaultContent, 8);
+  }
+};
+
+const uint8_t GOTAtom::_defaultContent[8] = {0};
+
+class PLTAtom : public SimpleDefinedAtom {
+  static const uint8_t _defaultContent[16];
+
+public:
+  PLTAtom(const File &f, GOTAtom *ga) : SimpleDefinedAtom(f) {
+    addReference(llvm::ELF::R_386_GOTPC, 2, ga, 0);
+  }
+
+  virtual ContentType contentType() const {
+    return DefinedAtom::typeStub;
+  }
+
+  virtual uint64_t size() const {
+    return rawContent().size();
+  }
+
+  virtual ContentPermissions permissions() const {
+    return DefinedAtom::permR_X;
+  }
+
+  virtual ArrayRef<uint8_t> rawContent() const {
+    return ArrayRef<uint8_t>(_defaultContent, 16);
+  }
+};
+
+const uint8_t PLTAtom::_defaultContent[16] = {
+    0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *gotatom(%rip)
+    0x68, 0x00, 0x00, 0x00, 0x00,       // pushq pltentry
+    0xe9, 0x00, 0x00, 0x00, 0x00        // jmpq plt[-1]
+  };
+
+class ELFPassFile : public SimpleFile {
+public:
+  ELFPassFile() : SimpleFile("ELFPassFile") {}
+
+  llvm::BumpPtrAllocator _alloc;
+};
+
+class PLTPass : public Pass {
+public:
+  PLTPass(const ELFTargetInfo &ti) : _targetInfo(ti) {}
+
+  virtual void perform(MutableFile &mf) {
+    for (const auto &atom : mf.defined())
+      for (const auto &ref : *atom) {
+        if (ref->kind() != llvm::ELF::R_X86_64_PC32)
+          continue;
+        if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref->target())){
+          if (da->contentType() != DefinedAtom::typeResolver)
+            continue;
+          // We have a PC32 call to a IFUNC. Create a plt and got entry.
+          auto ga = new (_file._alloc) GOTAtom(_file, da);
+          mf.addAtom(*ga);
+          auto pa = new (_file._alloc) PLTAtom(_file, ga);
+          mf.addAtom(*pa);
+          // This is dirty.
+          const_cast<Reference*>(ref)->setTarget(pa);
+        }
+      }
+    (void)_targetInfo;
+  }
+
+private:
+  ELFPassFile _file;
+  const ELFTargetInfo &_targetInfo;
+};
+
+class X86_64ELFTargetInfo LLVM_FINAL : public ELFTargetInfo {
+public:
+  X86_64ELFTargetInfo(const LinkerOptions &lo) : ELFTargetInfo(lo) {}
+
+  virtual uint64_t getPageSize() const { return 0x1000; }
+
+  virtual void addPasses(PassManager &pm) const {
+    pm.add(std::unique_ptr<Pass>(new PLTPass(*this)));
+  }
+};
+
 class HexagonELFTargetInfo LLVM_FINAL : public ELFTargetInfo {
 public:
   HexagonELFTargetInfo(const LinkerOptions &lo) : ELFTargetInfo(lo) {}
@@ -75,8 +187,9 @@
 std::unique_ptr<ELFTargetInfo> ELFTargetInfo::create(const LinkerOptions &lo) {
   switch (llvm::Triple(llvm::Triple::normalize(lo._target)).getArch()) {
   case llvm::Triple::x86:
-  case llvm::Triple::x86_64:
     return std::unique_ptr<ELFTargetInfo>(new X86ELFTargetInfo(lo));
+  case llvm::Triple::x86_64:
+    return std::unique_ptr<ELFTargetInfo>(new X86_64ELFTargetInfo(lo));
   case llvm::Triple::hexagon:
     return std::unique_ptr<ELFTargetInfo>(new HexagonELFTargetInfo(lo));
   case llvm::Triple::ppc:
Index: test/elf/Inputs/ifunc.cpp
===================================================================
--- /dev/null
+++ test/elf/Inputs/ifunc.cpp
@@ -0,0 +1,5 @@
+extern "C" int hey();
+
+int main() {
+  return hey();
+}
Index: test/elf/ifunc.test
===================================================================
--- test/elf/ifunc.test
+++ test/elf/ifunc.test
@@ -1,6 +1,27 @@
 RUN: lld -core -target x86_64-linux -emit-yaml -output=- %p/Inputs/ifunc.x86-64 \
 RUN: | FileCheck %s
+RUN: lld -core -target x86_64-linux -emit-yaml -output=- %p/Inputs/ifunc.x86-64 \
+RUN: %p/Inputs/ifunc.cpp.x86-64 | FileCheck %s --check-prefix=PLT
 
 CHECK: name: hey
 CHECK: scope: global
 CHECK: type: resolver
+
+// Get the target that main references.
+PLT: name: main
+PLT: scope: global
+PLT: references
+PLT: kind: 2
+PLT: target: [[PLTNAME:[a-zA-Z0-9]+]]
+
+// Make sure there's a got entry with a IRELATIVE relocation.
+PLT: type: got
+PLT: kind: 37
+
+// Make sure the target of main's relocation is a stub with a PC32 relocation.
+// This relocation is to the got atom, but you can't really write that check in
+// FileCheck.
+PLT: ref-name: [[PLTNAME]]
+PLT: type: stub
+PLT: references
+PLT: kind: 10
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D324.1.patch
Type: text/x-patch
Size: 5489 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20130123/63e0a67c/attachment.bin>


More information about the llvm-commits mailing list