]> granicus.if.org Git - llvm/commitdiff
ExecutionEngine: add preliminary support for COFF ARM
authorSaleem Abdulrasool <compnerd@compnerd.org>
Fri, 24 Jun 2016 14:11:44 +0000 (14:11 +0000)
committerSaleem Abdulrasool <compnerd@compnerd.org>
Fri, 24 Jun 2016 14:11:44 +0000 (14:11 +0000)
This adds rudimentary support for COFF ARM to the dynamic loader for the
exeuction engine.  This can be used by lldb to JIT code into a COFF ARM
environment.  This lays the foundation for the loader, though a few of the
relocation types are yet unhandled.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@273682 91177308-0d34-0410-b5e6-96231b3b80d8

lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.cpp
lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFThumb.h [new file with mode: 0644]
test/ExecutionEngine/RuntimeDyld/ARM/COFF_Thumb.s [new file with mode: 0644]

index f345b4700a3deaf82a5a83918808da8dd5d4beb5..24bd9a002c206efb843fe7a9842351875df2faa0 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "RuntimeDyldCOFF.h"
 #include "Targets/RuntimeDyldCOFFI386.h"
+#include "Targets/RuntimeDyldCOFFThumb.h"
 #include "Targets/RuntimeDyldCOFFX86_64.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/Triple.h"
@@ -45,11 +46,11 @@ llvm::RuntimeDyldCOFF::create(Triple::ArchType Arch,
                               RuntimeDyld::MemoryManager &MemMgr,
                               RuntimeDyld::SymbolResolver &Resolver) {
   switch (Arch) {
-  default:
-    llvm_unreachable("Unsupported target for RuntimeDyldCOFF.");
-    break;
+  default: llvm_unreachable("Unsupported target for RuntimeDyldCOFF.");
   case Triple::x86:
     return make_unique<RuntimeDyldCOFFI386>(MemMgr, Resolver);
+  case Triple::thumb:
+    return make_unique<RuntimeDyldCOFFThumb>(MemMgr, Resolver);
   case Triple::x86_64:
     return make_unique<RuntimeDyldCOFFX86_64>(MemMgr, Resolver);
   }
@@ -57,9 +58,9 @@ llvm::RuntimeDyldCOFF::create(Triple::ArchType Arch,
 
 std::unique_ptr<RuntimeDyld::LoadedObjectInfo>
 RuntimeDyldCOFF::loadObject(const object::ObjectFile &O) {
-  if (auto ObjSectionToIDOrErr = loadObjectImpl(O))
+  if (auto ObjSectionToIDOrErr = loadObjectImpl(O)) {
     return llvm::make_unique<LoadedCOFFObjectInfo>(*this, *ObjSectionToIDOrErr);
-  else {
+  else {
     HasError = true;
     raw_string_ostream ErrStream(ErrorStr);
     logAllUnhandledErrors(ObjSectionToIDOrErr.takeError(), ErrStream, "");
diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFThumb.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFThumb.h
new file mode 100644 (file)
index 0000000..bcd2860
--- /dev/null
@@ -0,0 +1,288 @@
+//===--- RuntimeDyldCOFFThumb.h --- COFF/Thumb specific code ---*- C++ --*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// COFF thumb support for MC-JIT runtime dynamic linker.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H
+#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H
+
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/COFF.h"
+#include "../RuntimeDyldCOFF.h"
+
+#define DEBUG_TYPE "dyld"
+
+namespace llvm {
+
+class RuntimeDyldCOFFThumb : public RuntimeDyldCOFF {
+public:
+  RuntimeDyldCOFFThumb(RuntimeDyld::MemoryManager &MM,
+                       RuntimeDyld::SymbolResolver &Resolver)
+      : RuntimeDyldCOFF(MM, Resolver) {}
+
+  unsigned getMaxStubSize() override {
+    return 16; // 8-byte load instructions, 4-byte jump, 4-byte padding
+  }
+
+  unsigned getStubAlignment() override { return 1; }
+
+  Expected<relocation_iterator>
+  processRelocationRef(unsigned SectionID,
+                       relocation_iterator RelI,
+                       const ObjectFile &Obj,
+                       ObjSectionToIDMap &ObjSectionToID,
+                       StubMap &Stubs) override {
+    auto Symbol = RelI->getSymbol();
+    if (Symbol == Obj.symbol_end())
+      report_fatal_error("Unknown symbol in relocation");
+
+    Expected<StringRef> TargetNameOrErr = Symbol->getName();
+    if (!TargetNameOrErr)
+      return TargetNameOrErr.takeError();
+    StringRef TargetName = *TargetNameOrErr;
+
+    auto SectionOrErr = Symbol->getSection();
+    if (!SectionOrErr)
+      return SectionOrErr.takeError();
+    auto Section = *SectionOrErr;
+
+    uint64_t RelType = RelI->getType();
+    uint64_t Offset = RelI->getOffset();
+
+    // Determine the Addend used to adjust the relocation value.
+    uint64_t Addend = 0;
+    SectionEntry &AddendSection = Sections[SectionID];
+    uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset;
+    uint8_t *Displacement = (uint8_t *)ObjTarget;
+
+    switch (RelType) {
+    case COFF::IMAGE_REL_ARM_ADDR32:
+    case COFF::IMAGE_REL_ARM_ADDR32NB:
+    case COFF::IMAGE_REL_ARM_SECREL:
+      Addend = readBytesUnaligned(Displacement, 4);
+      break;
+    default:
+      break;
+    }
+
+#if !defined(NDEBUG)
+    SmallString<32> RelTypeName;
+    RelI->getTypeName(RelTypeName);
+#endif
+    DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
+                 << " RelType: " << RelTypeName << " TargetName: " << TargetName
+                 << " Addend " << Addend << "\n");
+
+    unsigned TargetSectionID = -1;
+    if (Section == Obj.section_end()) {
+      RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0);
+      addRelocationForSymbol(RE, TargetName);
+    } else {
+      if (auto TargetSectionIDOrErr =
+          findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID))
+        TargetSectionID = *TargetSectionIDOrErr;
+      else
+        return TargetSectionIDOrErr.takeError();
+
+      switch (RelType) {
+      default: llvm_unreachable("unsupported relocation type");
+      case COFF::IMAGE_REL_ARM_ABSOLUTE:
+        // This relocation is ignored.
+        break;
+      case COFF::IMAGE_REL_ARM_ADDR32:
+      case COFF::IMAGE_REL_ARM_ADDR32NB: {
+        RelocationEntry RE =
+            RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
+                            getSymbolOffset(*Symbol), 0, 0, false, 0);
+        addRelocationForSection(RE, TargetSectionID);
+        break;
+      }
+      case COFF::IMAGE_REL_ARM_SECTION: {
+        RelocationEntry RE =
+            RelocationEntry(TargetSectionID, Offset, RelType, 0);
+        addRelocationForSection(RE, TargetSectionID);
+        break;
+      }
+      case COFF::IMAGE_REL_ARM_SECREL: {
+        RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType,
+                                             getSymbolOffset(*Symbol) + Addend);
+        addRelocationForSection(RE, TargetSectionID);
+        break;
+      }
+      case COFF::IMAGE_REL_ARM_MOV32T: {
+        RelocationEntry RE =
+            RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
+                            getSymbolOffset(*Symbol), 0, 0, false, 0);
+        addRelocationForSection(RE, TargetSectionID);
+        break;
+      }
+      case COFF::IMAGE_REL_ARM_BRANCH20T:
+      case COFF::IMAGE_REL_ARM_BRANCH24T:
+      case COFF::IMAGE_REL_ARM_BLX23T: {
+        RelocationEntry RE =
+            RelocationEntry(SectionID, Offset, RelType,
+                            getSymbolOffset(*Symbol) + Addend, true, 0);
+        addRelocationForSection(RE, TargetSectionID);
+        break;
+      }
+      }
+    }
+
+    return ++RelI;
+  }
+
+  void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
+    const auto Section = Sections[RE.SectionID];
+    uint8_t *Target = Section.getAddressWithOffset(RE.Offset);
+
+    switch (RE.RelType) {
+    default: llvm_unreachable("unsupported relocation type");
+    case COFF::IMAGE_REL_ARM_ABSOLUTE:
+      // This relocation is ignored.
+      break;
+    case COFF::IMAGE_REL_ARM_ADDR32: {
+      // The target's 32-bit VA.
+      uint64_t Result =
+          RE.Sections.SectionA == static_cast<uint32_t>(-1)
+              ? Value
+              : Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);
+      assert(static_cast<int32_t>(Result) <= INT32_MAX &&
+             "relocation overflow");
+      assert(static_cast<int32_t>(Result) >= INT32_MIN &&
+             "relocation underflow");
+      DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
+                   << " RelType: IMAGE_REL_ARM_ADDR32"
+                   << " TargetSection: " << RE.Sections.SectionA
+                   << " Value: " << format("0x%08" PRIx32, Result) << '\n');
+      writeBytesUnaligned(Result, Target, 4);
+      break;
+    }
+    case COFF::IMAGE_REL_ARM_ADDR32NB: {
+      // The target's 32-bit RVA.
+      // NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase
+      uint64_t Result = Sections[RE.Sections.SectionA].getLoadAddress() -
+                        Sections[0].getLoadAddress() + RE.Addend;
+      assert(static_cast<int32_t>(Result) <= INT32_MAX &&
+             "relocation overflow");
+      assert(static_cast<int32_t>(Result) >= INT32_MIN &&
+             "relocation underflow");
+      DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
+                   << " RelType: IMAGE_REL_ARM_ADDR32NB"
+                   << " TargetSection: " << RE.Sections.SectionA
+                   << " Value: " << format("0x%08" PRIx32, Result) << '\n');
+      writeBytesUnaligned(Result, Target, 4);
+      break;
+    }
+    case COFF::IMAGE_REL_ARM_SECTION:
+      // 16-bit section index of the section that contains the target.
+      assert(static_cast<int32_t>(RE.SectionID) <= INT16_MAX &&
+             "relocation overflow");
+      assert(static_cast<int32_t>(RE.SectionID) >= INT16_MIN &&
+             "relocation underflow");
+      DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
+                   << " RelType: IMAGE_REL_ARM_SECTION Value: " << RE.SectionID
+                   << '\n');
+      writeBytesUnaligned(RE.SectionID, Target, 2);
+      break;
+    case COFF::IMAGE_REL_ARM_SECREL:
+      // 32-bit offset of the target from the beginning of its section.
+      assert(static_cast<int32_t>(RE.Addend) <= INT32_MAX &&
+             "relocation overflow");
+      assert(static_cast<int32_t>(RE.Addend) >= INT32_MIN &&
+             "relocation underflow");
+      DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
+                   << " RelType: IMAGE_REL_ARM_SECREL Value: " << RE.Addend
+                   << '\n');
+      writeBytesUnaligned(RE.Addend, Target, 2);
+      break;
+    case COFF::IMAGE_REL_ARM_MOV32T: {
+      // 32-bit VA of the target applied to a contiguous MOVW+MOVT pair.
+      uint64_t Result =
+          Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);
+      assert(static_cast<int32_t>(Result) <= INT32_MAX &&
+             "relocation overflow");
+      assert(static_cast<int32_t>(Result) >= INT32_MIN &&
+             "relocation underflow");
+      DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
+                   << " RelType: IMAGE_REL_ARM_MOV32T"
+                   << " TargetSection: " << RE.Sections.SectionA
+                   << " Value: " << format("0x%08" PRIx32, Result) << '\n');
+
+      // MOVW(T3): |11110|i|10|0|1|0|0|imm4|0|imm3|Rd|imm8|
+      //            imm32 = zext imm4:i:imm3:imm8
+      // MOVT(T1): |11110|i|10|1|1|0|0|imm4|0|imm3|Rd|imm8|
+      //            imm16 =      imm4:i:imm3:imm8
+
+      auto EncodeImmediate = [](uint8_t *Bytes, uint16_t Immediate)  {
+        Bytes[0] |= ((Immediate & 0xf000) >> 12);
+        Bytes[1] |= ((Immediate & 0x0800) >> 11);
+        Bytes[2] |= ((Immediate & 0x00ff) >>  0);
+        Bytes[3] |= ((Immediate & 0x0700) >>  8);
+      };
+
+      EncodeImmediate(&Target[0], static_cast<uint32_t>(Result) >> 00);
+      EncodeImmediate(&Target[4], static_cast<uint32_t>(Result) >> 16);
+
+      break;
+    }
+    case COFF::IMAGE_REL_ARM_BRANCH20T: {
+      // The most significant 20-bits of the signed 21-bit relative displacement
+      uint64_t Value =
+          RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
+      assert(static_cast<int32_t>(RE.Addend) <= INT32_MAX &&
+             "relocation overflow");
+      assert(static_cast<int32_t>(RE.Addend) >= INT32_MIN &&
+             "relocation underflow");
+      DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
+                   << " RelType: IMAGE_REL_ARM_BRANCH20T"
+                   << " Value: " << static_cast<int32_t>(Value) << '\n');
+      llvm_unreachable("unimplemented relocation");
+      break;
+    }
+    case COFF::IMAGE_REL_ARM_BRANCH24T: {
+      // The most significant 24-bits of the signed 25-bit relative displacement
+      uint64_t Value =
+          RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
+      assert(static_cast<int32_t>(RE.Addend) <= INT32_MAX &&
+             "relocation overflow");
+      assert(static_cast<int32_t>(RE.Addend) >= INT32_MIN &&
+             "relocation underflow");
+      DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
+                   << " RelType: IMAGE_REL_ARM_BRANCH24T"
+                   << " Value: " << static_cast<int32_t>(Value) << '\n');
+      llvm_unreachable("unimplemented relocation");
+      break;
+    }
+    case COFF::IMAGE_REL_ARM_BLX23T: {
+      // The most significant 24-bits of the signed 25-bit relative displacement
+      uint64_t Value =
+          RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
+      assert(static_cast<int32_t>(RE.Addend) <= INT32_MAX &&
+             "relocation overflow");
+      assert(static_cast<int32_t>(RE.Addend) >= INT32_MIN &&
+             "relocation underflow");
+      DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
+                   << " RelType: IMAGE_REL_ARM_BLX23T"
+                   << " Value: " << static_cast<int32_t>(Value) << '\n');
+      llvm_unreachable("unimplemented relocation");
+      break;
+    }
+    }
+  }
+
+  void registerEHFrames() override {}
+  void deregisterEHFrames() override {}
+};
+
+}
+
+#endif
+
diff --git a/test/ExecutionEngine/RuntimeDyld/ARM/COFF_Thumb.s b/test/ExecutionEngine/RuntimeDyld/ARM/COFF_Thumb.s
new file mode 100644 (file)
index 0000000..2a12812
--- /dev/null
@@ -0,0 +1,107 @@
+// RUN: llvm-mc -triple thumbv7-windows-itanium -filetype obj -o %t.obj %s
+// RUN: llvm-rtdyld -triple thumbv7-windows -dummy-extern OutputDebugStringA=0x78563412 -dummy-extern ExitProcess=0x54769890 -dummy-extern unnamed_addr=0x00001024 -verify -check %s %t.obj
+
+       .text
+       .syntax unified
+
+       .def unnamed_addr
+               .scl 2
+               .type 32
+       .endef
+       .global unnamed_addr
+
+       .def branch24t
+               .scl 2
+               .type 32
+       .endef
+       .global branch24t
+       .p2align 1
+       .code 16
+       .thumb_func
+branch24t:
+@ rel1:
+#      b unnamed_addr                                  @ IMAGE_REL_ARM_BRANCH24T
+
+       .def function
+               .scl 2
+               .type 32
+       .endef
+       .globl function
+       .p2align 1
+       .code 16
+       .thumb_func
+function:
+       push.w {r11, lr}
+       mov r11, sp
+rel2:                                                  @ IMAGE_REL_ARM_MOV32T
+       movw r0, :lower16:__imp_OutputDebugStringA
+# rtdyld-check: decode_operand(rel2, 1) = (__imp_OutputDebugStringA&0x0000ffff)
+       movt r0, :upper16:__imp_OutputDebugStringA
+# TODO rtdyld-check: decode_operand(rel2, 1) = (__imp_OutputDebugStringA&0xffff0000>>16)
+       ldr r1, [r0]
+rel3:                                                  @ IMAGE_REL_ARM_MOV32T
+       movw r0, :lower16:string
+# rtdyld-check: decode_operand(rel3, 1) = (string&0x0000ffff)
+       movt r0, :upper16:string
+# TODO rtdyld-check: decode_operand(rel3, 1) = (string&0xffff0000>>16)
+       blx r1
+rel4:                                                  @ IMAGE_REL_ARM_MOV32T
+       movw r0, :lower16:__imp_ExitProcess
+# rtdyld-check: decode_operand(rel4, 1) = (__imp_ExitProcess&0x0000ffff)
+       movt r0, :upper16:__imp_ExitProcess
+# TODO rtdyld-check: decode_operand(rel4, 1) = (__imp_ExitProcess&0xffff0000>>16)
+       ldr r1, [r0]
+       movs r0, #0
+       pop.w {r11, lr}
+       bx r1
+
+       .def main
+               .scl 2
+               .type 32
+       .endef
+       .globl main
+       .p2align 1
+       .code 16
+       .thumb_func
+main:
+       push.w {r11, lr}
+       mov r11, sp
+rel5:
+#      bl function                                     @ IMAGE_REL_ARM_BLX23T
+       movs r0, #0
+       pop.w {r11, pc}
+
+       .section .rdata,"dr"
+       .global string
+string:
+       .asciz "Hello World\n"
+
+       .data
+
+       .p2align 2
+__imp_OutputDebugStringA:
+@ rel6:
+       .long OutputDebugStringA                        @ IMAGE_REL_ARM_ADDR32
+# rtdyld-check: *{4}__imp_OutputDebugStringA = 0x78563412
+
+       .p2align 2
+__imp_ExitProcess:
+@ rel7:
+       .long ExitProcess                               @ IMAGE_REL_ARM_ADDR32
+# rtdyld-check: *{4}__imp_ExitProcess = 0x54769890
+
+       .global relocations
+relocations:
+@ rel8:
+       .long function(imgrel)                          @ IMAGE_REL_ARM_ADDR32NB
+# rtdyld-check: *{4}relocations = function - section_addr(COFF_Thumb.s.tmp.obj, .text)
+rel9:
+       .secidx __imp_OutputDebugStringA                @ IMAGE_REL_ARM_SECTION
+# rtdyld-check: *{2}rel9 = 1
+rel10:
+       .long relocations(secrel32)                     @ IMAGE_REL_ARM_SECREL
+# rtdyld-check: *{4}rel10 = relocations - section_addr(COFF_Thumb.s.tmp.obj, .data)
+rel11:
+       .secrel32 relocations                           @ IMAGE_REL_ARM_SECREL
+# rtdyld-check: *{4}rel11 = relocations - section_addr(COFF_Thumb.s.tmp.obj, .data)
+