Home | History | Annotate | Download | only in Targets
      1 //===--- RuntimeDyldCOFFThumb.h --- COFF/Thumb specific code ---*- C++ --*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // COFF thumb support for MC-JIT runtime dynamic linker.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H
     15 #define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H
     16 
     17 #include "llvm/Object/COFF.h"
     18 #include "llvm/Support/COFF.h"
     19 #include "../RuntimeDyldCOFF.h"
     20 
     21 #define DEBUG_TYPE "dyld"
     22 
     23 namespace llvm {
     24 
     25 class RuntimeDyldCOFFThumb : public RuntimeDyldCOFF {
     26 public:
     27   RuntimeDyldCOFFThumb(RuntimeDyld::MemoryManager &MM,
     28                        RuntimeDyld::SymbolResolver &Resolver)
     29       : RuntimeDyldCOFF(MM, Resolver) {}
     30 
     31   unsigned getMaxStubSize() override {
     32     return 16; // 8-byte load instructions, 4-byte jump, 4-byte padding
     33   }
     34 
     35   unsigned getStubAlignment() override { return 1; }
     36 
     37   Expected<relocation_iterator>
     38   processRelocationRef(unsigned SectionID,
     39                        relocation_iterator RelI,
     40                        const ObjectFile &Obj,
     41                        ObjSectionToIDMap &ObjSectionToID,
     42                        StubMap &Stubs) override {
     43     auto Symbol = RelI->getSymbol();
     44     if (Symbol == Obj.symbol_end())
     45       report_fatal_error("Unknown symbol in relocation");
     46 
     47     Expected<StringRef> TargetNameOrErr = Symbol->getName();
     48     if (!TargetNameOrErr)
     49       return TargetNameOrErr.takeError();
     50     StringRef TargetName = *TargetNameOrErr;
     51 
     52     auto SectionOrErr = Symbol->getSection();
     53     if (!SectionOrErr)
     54       return SectionOrErr.takeError();
     55     auto Section = *SectionOrErr;
     56 
     57     uint64_t RelType = RelI->getType();
     58     uint64_t Offset = RelI->getOffset();
     59 
     60     // Determine the Addend used to adjust the relocation value.
     61     uint64_t Addend = 0;
     62     SectionEntry &AddendSection = Sections[SectionID];
     63     uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset;
     64     uint8_t *Displacement = (uint8_t *)ObjTarget;
     65 
     66     switch (RelType) {
     67     case COFF::IMAGE_REL_ARM_ADDR32:
     68     case COFF::IMAGE_REL_ARM_ADDR32NB:
     69     case COFF::IMAGE_REL_ARM_SECREL:
     70       Addend = readBytesUnaligned(Displacement, 4);
     71       break;
     72     default:
     73       break;
     74     }
     75 
     76 #if !defined(NDEBUG)
     77     SmallString<32> RelTypeName;
     78     RelI->getTypeName(RelTypeName);
     79 #endif
     80     DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
     81                  << " RelType: " << RelTypeName << " TargetName: " << TargetName
     82                  << " Addend " << Addend << "\n");
     83 
     84     unsigned TargetSectionID = -1;
     85     if (Section == Obj.section_end()) {
     86       RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0);
     87       addRelocationForSymbol(RE, TargetName);
     88     } else {
     89       if (auto TargetSectionIDOrErr =
     90           findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID))
     91         TargetSectionID = *TargetSectionIDOrErr;
     92       else
     93         return TargetSectionIDOrErr.takeError();
     94 
     95       switch (RelType) {
     96       default: llvm_unreachable("unsupported relocation type");
     97       case COFF::IMAGE_REL_ARM_ABSOLUTE:
     98         // This relocation is ignored.
     99         break;
    100       case COFF::IMAGE_REL_ARM_ADDR32:
    101       case COFF::IMAGE_REL_ARM_ADDR32NB: {
    102         RelocationEntry RE =
    103             RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
    104                             getSymbolOffset(*Symbol), 0, 0, false, 0);
    105         addRelocationForSection(RE, TargetSectionID);
    106         break;
    107       }
    108       case COFF::IMAGE_REL_ARM_SECTION: {
    109         RelocationEntry RE =
    110             RelocationEntry(TargetSectionID, Offset, RelType, 0);
    111         addRelocationForSection(RE, TargetSectionID);
    112         break;
    113       }
    114       case COFF::IMAGE_REL_ARM_SECREL: {
    115         RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType,
    116                                              getSymbolOffset(*Symbol) + Addend);
    117         addRelocationForSection(RE, TargetSectionID);
    118         break;
    119       }
    120       case COFF::IMAGE_REL_ARM_MOV32T: {
    121         RelocationEntry RE =
    122             RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
    123                             getSymbolOffset(*Symbol), 0, 0, false, 0);
    124         addRelocationForSection(RE, TargetSectionID);
    125         break;
    126       }
    127       case COFF::IMAGE_REL_ARM_BRANCH20T:
    128       case COFF::IMAGE_REL_ARM_BRANCH24T:
    129       case COFF::IMAGE_REL_ARM_BLX23T: {
    130         RelocationEntry RE =
    131             RelocationEntry(SectionID, Offset, RelType,
    132                             getSymbolOffset(*Symbol) + Addend, true, 0);
    133         addRelocationForSection(RE, TargetSectionID);
    134         break;
    135       }
    136       }
    137     }
    138 
    139     return ++RelI;
    140   }
    141 
    142   void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
    143     const auto Section = Sections[RE.SectionID];
    144     uint8_t *Target = Section.getAddressWithOffset(RE.Offset);
    145 
    146     switch (RE.RelType) {
    147     default: llvm_unreachable("unsupported relocation type");
    148     case COFF::IMAGE_REL_ARM_ABSOLUTE:
    149       // This relocation is ignored.
    150       break;
    151     case COFF::IMAGE_REL_ARM_ADDR32: {
    152       // The target's 32-bit VA.
    153       uint64_t Result =
    154           RE.Sections.SectionA == static_cast<uint32_t>(-1)
    155               ? Value
    156               : Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);
    157       assert(static_cast<int32_t>(Result) <= INT32_MAX &&
    158              "relocation overflow");
    159       assert(static_cast<int32_t>(Result) >= INT32_MIN &&
    160              "relocation underflow");
    161       DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
    162                    << " RelType: IMAGE_REL_ARM_ADDR32"
    163                    << " TargetSection: " << RE.Sections.SectionA
    164                    << " Value: " << format("0x%08" PRIx32, Result) << '\n');
    165       writeBytesUnaligned(Result, Target, 4);
    166       break;
    167     }
    168     case COFF::IMAGE_REL_ARM_ADDR32NB: {
    169       // The target's 32-bit RVA.
    170       // NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase
    171       uint64_t Result = Sections[RE.Sections.SectionA].getLoadAddress() -
    172                         Sections[0].getLoadAddress() + RE.Addend;
    173       assert(static_cast<int32_t>(Result) <= INT32_MAX &&
    174              "relocation overflow");
    175       assert(static_cast<int32_t>(Result) >= INT32_MIN &&
    176              "relocation underflow");
    177       DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
    178                    << " RelType: IMAGE_REL_ARM_ADDR32NB"
    179                    << " TargetSection: " << RE.Sections.SectionA
    180                    << " Value: " << format("0x%08" PRIx32, Result) << '\n');
    181       writeBytesUnaligned(Result, Target, 4);
    182       break;
    183     }
    184     case COFF::IMAGE_REL_ARM_SECTION:
    185       // 16-bit section index of the section that contains the target.
    186       assert(static_cast<int32_t>(RE.SectionID) <= INT16_MAX &&
    187              "relocation overflow");
    188       assert(static_cast<int32_t>(RE.SectionID) >= INT16_MIN &&
    189              "relocation underflow");
    190       DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
    191                    << " RelType: IMAGE_REL_ARM_SECTION Value: " << RE.SectionID
    192                    << '\n');
    193       writeBytesUnaligned(RE.SectionID, Target, 2);
    194       break;
    195     case COFF::IMAGE_REL_ARM_SECREL:
    196       // 32-bit offset of the target from the beginning of its section.
    197       assert(static_cast<int32_t>(RE.Addend) <= INT32_MAX &&
    198              "relocation overflow");
    199       assert(static_cast<int32_t>(RE.Addend) >= INT32_MIN &&
    200              "relocation underflow");
    201       DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
    202                    << " RelType: IMAGE_REL_ARM_SECREL Value: " << RE.Addend
    203                    << '\n');
    204       writeBytesUnaligned(RE.Addend, Target, 2);
    205       break;
    206     case COFF::IMAGE_REL_ARM_MOV32T: {
    207       // 32-bit VA of the target applied to a contiguous MOVW+MOVT pair.
    208       uint64_t Result =
    209           Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);
    210       assert(static_cast<int32_t>(Result) <= INT32_MAX &&
    211              "relocation overflow");
    212       assert(static_cast<int32_t>(Result) >= INT32_MIN &&
    213              "relocation underflow");
    214       DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
    215                    << " RelType: IMAGE_REL_ARM_MOV32T"
    216                    << " TargetSection: " << RE.Sections.SectionA
    217                    << " Value: " << format("0x%08" PRIx32, Result) << '\n');
    218 
    219       // MOVW(T3): |11110|i|10|0|1|0|0|imm4|0|imm3|Rd|imm8|
    220       //            imm32 = zext imm4:i:imm3:imm8
    221       // MOVT(T1): |11110|i|10|1|1|0|0|imm4|0|imm3|Rd|imm8|
    222       //            imm16 =      imm4:i:imm3:imm8
    223 
    224       auto EncodeImmediate = [](uint8_t *Bytes, uint16_t Immediate)  {
    225         Bytes[0] |= ((Immediate & 0xf000) >> 12);
    226         Bytes[1] |= ((Immediate & 0x0800) >> 11);
    227         Bytes[2] |= ((Immediate & 0x00ff) >>  0);
    228         Bytes[3] |= ((Immediate & 0x0700) >>  8);
    229       };
    230 
    231       EncodeImmediate(&Target[0], static_cast<uint32_t>(Result) >> 00);
    232       EncodeImmediate(&Target[4], static_cast<uint32_t>(Result) >> 16);
    233 
    234       break;
    235     }
    236     case COFF::IMAGE_REL_ARM_BRANCH20T: {
    237       // The most significant 20-bits of the signed 21-bit relative displacement
    238       uint64_t Value =
    239           RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
    240       assert(static_cast<int32_t>(RE.Addend) <= INT32_MAX &&
    241              "relocation overflow");
    242       assert(static_cast<int32_t>(RE.Addend) >= INT32_MIN &&
    243              "relocation underflow");
    244       DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
    245                    << " RelType: IMAGE_REL_ARM_BRANCH20T"
    246                    << " Value: " << static_cast<int32_t>(Value) << '\n');
    247       static_cast<void>(Value);
    248       llvm_unreachable("unimplemented relocation");
    249       break;
    250     }
    251     case COFF::IMAGE_REL_ARM_BRANCH24T: {
    252       // The most significant 24-bits of the signed 25-bit relative displacement
    253       uint64_t Value =
    254           RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
    255       assert(static_cast<int32_t>(RE.Addend) <= INT32_MAX &&
    256              "relocation overflow");
    257       assert(static_cast<int32_t>(RE.Addend) >= INT32_MIN &&
    258              "relocation underflow");
    259       DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
    260                    << " RelType: IMAGE_REL_ARM_BRANCH24T"
    261                    << " Value: " << static_cast<int32_t>(Value) << '\n');
    262       static_cast<void>(Value);
    263       llvm_unreachable("unimplemented relocation");
    264       break;
    265     }
    266     case COFF::IMAGE_REL_ARM_BLX23T: {
    267       // The most significant 24-bits of the signed 25-bit relative displacement
    268       uint64_t Value =
    269           RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
    270       assert(static_cast<int32_t>(RE.Addend) <= INT32_MAX &&
    271              "relocation overflow");
    272       assert(static_cast<int32_t>(RE.Addend) >= INT32_MIN &&
    273              "relocation underflow");
    274       DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
    275                    << " RelType: IMAGE_REL_ARM_BLX23T"
    276                    << " Value: " << static_cast<int32_t>(Value) << '\n');
    277       static_cast<void>(Value);
    278       llvm_unreachable("unimplemented relocation");
    279       break;
    280     }
    281     }
    282   }
    283 
    284   void registerEHFrames() override {}
    285   void deregisterEHFrames() override {}
    286 };
    287 
    288 }
    289 
    290 #endif
    291 
    292