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