LCOV - code coverage report
Current view: top level - lib/ExecutionEngine/RuntimeDyld/Targets - RuntimeDyldCOFFThumb.h (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 77 95 81.1 %
Date: 2018-06-17 00:07:59 Functions: 7 8 87.5 %
Legend: Lines: hit not hit

          Line data    Source code
       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          10 : static bool isThumbFunc(symbol_iterator Symbol, const ObjectFile &Obj,
      26             :                         section_iterator Section) {
      27             :   Expected<SymbolRef::Type> SymTypeOrErr = Symbol->getType();
      28          10 :   if (!SymTypeOrErr) {
      29             :     std::string Buf;
      30             :     raw_string_ostream OS(Buf);
      31           0 :     logAllUnhandledErrors(SymTypeOrErr.takeError(), OS, "");
      32             :     OS.flush();
      33           0 :     report_fatal_error(Buf);
      34             :   }
      35             : 
      36          10 :   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           4 :   return cast<COFFObjectFile>(Obj).getCOFFSection(*Section)->Characteristics &
      42           2 :          COFF::IMAGE_SCN_MEM_16BIT;
      43             : }
      44             : 
      45           2 : class RuntimeDyldCOFFThumb : public RuntimeDyldCOFF {
      46             : public:
      47             :   RuntimeDyldCOFFThumb(RuntimeDyld::MemoryManager &MM,
      48             :                        JITSymbolResolver &Resolver)
      49           1 :       : RuntimeDyldCOFF(MM, Resolver) {}
      50             : 
      51           4 :   unsigned getMaxStubSize() override {
      52           4 :     return 16; // 8-byte load instructions, 4-byte jump, 4-byte padding
      53             :   }
      54             : 
      55           6 :   unsigned getStubAlignment() override { return 1; }
      56             : 
      57             :   Expected<relocation_iterator>
      58          13 :   processRelocationRef(unsigned SectionID,
      59             :                        relocation_iterator RelI,
      60             :                        const ObjectFile &Obj,
      61             :                        ObjSectionToIDMap &ObjSectionToID,
      62             :                        StubMap &Stubs) override {
      63          13 :     auto Symbol = RelI->getSymbol();
      64          26 :     if (Symbol == Obj.symbol_end())
      65           0 :       report_fatal_error("Unknown symbol in relocation");
      66             : 
      67             :     Expected<StringRef> TargetNameOrErr = Symbol->getName();
      68          13 :     if (!TargetNameOrErr)
      69             :       return TargetNameOrErr.takeError();
      70          13 :     StringRef TargetName = *TargetNameOrErr;
      71             : 
      72             :     auto SectionOrErr = Symbol->getSection();
      73          13 :     if (!SectionOrErr)
      74             :       return SectionOrErr.takeError();
      75          13 :     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          13 :     SectionEntry &AddendSection = Sections[SectionID];
      83          13 :     uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset;
      84          13 :     uint8_t *Displacement = (uint8_t *)ObjTarget;
      85             : 
      86             :     switch (RelType) {
      87           6 :     case COFF::IMAGE_REL_ARM_ADDR32:
      88             :     case COFF::IMAGE_REL_ARM_ADDR32NB:
      89             :     case COFF::IMAGE_REL_ARM_SECREL:
      90           6 :       Addend = readBytesUnaligned(Displacement, 4);
      91           6 :       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          26 :     if (Section == Obj.section_end()) {
     106           3 :       RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0);
     107           3 :       addRelocationForSymbol(RE, TargetName);
     108             :     } else {
     109          10 :       if (auto TargetSectionIDOrErr =
     110          20 :           findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID))
     111          10 :         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          10 :       bool IsTargetThumbFunc = isThumbFunc(Symbol, Obj, Section);
     118             : 
     119          10 :       switch (RelType) {
     120           0 :       default: llvm_unreachable("unsupported relocation type");
     121             :       case COFF::IMAGE_REL_ARM_ABSOLUTE:
     122             :         // This relocation is ignored.
     123             :         break;
     124           0 :       case COFF::IMAGE_REL_ARM_ADDR32: {
     125             :         RelocationEntry RE = RelocationEntry(
     126             :             SectionID, Offset, RelType, Addend, TargetSectionID,
     127           0 :             getSymbolOffset(*Symbol), 0, 0, false, 0, IsTargetThumbFunc);
     128           0 :         addRelocationForSection(RE, TargetSectionID);
     129             :         break;
     130             :       }
     131           1 :       case COFF::IMAGE_REL_ARM_ADDR32NB: {
     132             :         RelocationEntry RE =
     133             :             RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
     134           1 :                             getSymbolOffset(*Symbol), 0, 0, false, 0);
     135           1 :         addRelocationForSection(RE, TargetSectionID);
     136             :         break;
     137             :       }
     138           1 :       case COFF::IMAGE_REL_ARM_SECTION: {
     139             :         RelocationEntry RE =
     140           1 :             RelocationEntry(TargetSectionID, Offset, RelType, 0);
     141           1 :         addRelocationForSection(RE, TargetSectionID);
     142             :         break;
     143             :       }
     144           2 :       case COFF::IMAGE_REL_ARM_SECREL: {
     145             :         RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType,
     146           2 :                                              getSymbolOffset(*Symbol) + Addend);
     147           2 :         addRelocationForSection(RE, TargetSectionID);
     148             :         break;
     149             :       }
     150           6 :       case COFF::IMAGE_REL_ARM_MOV32T: {
     151             :         RelocationEntry RE = RelocationEntry(
     152             :             SectionID, Offset, RelType, Addend, TargetSectionID,
     153           6 :             getSymbolOffset(*Symbol), 0, 0, false, 0, IsTargetThumbFunc);
     154           6 :         addRelocationForSection(RE, TargetSectionID);
     155             :         break;
     156             :       }
     157           0 :       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           0 :                             getSymbolOffset(*Symbol) + Addend, true, 0);
     163           0 :         addRelocationForSection(RE, TargetSectionID);
     164             :         break;
     165             :       }
     166             :       }
     167             :     }
     168             : 
     169             :     return ++RelI;
     170             :   }
     171             : 
     172          13 :   void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
     173          26 :     const auto Section = Sections[RE.SectionID];
     174          13 :     uint8_t *Target = Section.getAddressWithOffset(RE.Offset);
     175          13 :     int ISASelectionBit = RE.IsTargetThumbFunc ? 1 : 0;
     176             : 
     177          13 :     switch (RE.RelType) {
     178           0 :     default: llvm_unreachable("unsupported relocation type");
     179             :     case COFF::IMAGE_REL_ARM_ABSOLUTE:
     180             :       // This relocation is ignored.
     181             :       break;
     182           3 :     case COFF::IMAGE_REL_ARM_ADDR32: {
     183             :       // The target's 32-bit VA.
     184             :       uint64_t Result =
     185           3 :           RE.Sections.SectionA == static_cast<uint32_t>(-1)
     186           3 :               ? Value
     187           0 :               : Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);
     188           3 :       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           3 :       writeBytesUnaligned(Result, Target, 4);
     196           3 :       break;
     197             :     }
     198           1 :     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           3 :       uint64_t Result = Sections[RE.Sections.SectionA].getLoadAddress() -
     202           2 :                         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           1 :       Result |= ISASelectionBit;
     210           1 :       writeBytesUnaligned(Result, Target, 4);
     211           1 :       break;
     212             :     }
     213           1 :     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           1 :       writeBytesUnaligned(RE.SectionID, Target, 2);
     221           1 :       break;
     222           2 :     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           2 :       writeBytesUnaligned(RE.Addend, Target, 2);
     230           2 :       break;
     231           6 :     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          12 :           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          12 :         Bytes[0] |= ((Immediate & 0xf000) >> 12);
     249          12 :         Bytes[1] |= ((Immediate & 0x0800) >> 11);
     250          12 :         Bytes[2] |= ((Immediate & 0x00ff) >>  0);
     251          12 :         Bytes[3] |= (((Immediate & 0x0700) >>  8) << 4);
     252             :       };
     253             : 
     254           6 :       EncodeImmediate(&Target[0],
     255           6 :                       (static_cast<uint32_t>(Result) >> 00) | ISASelectionBit);
     256           6 :       EncodeImmediate(&Target[4], static_cast<uint32_t>(Result) >> 16);
     257             : 
     258             :       break;
     259             :     }
     260           0 :     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           0 :       llvm_unreachable("unimplemented relocation");
     273             :       break;
     274             :     }
     275           0 :     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           0 :       llvm_unreachable("unimplemented relocation");
     288             :       break;
     289             :     }
     290           0 :     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           0 :       llvm_unreachable("unimplemented relocation");
     303             :       break;
     304             :     }
     305             :     }
     306          13 :   }
     307             : 
     308           1 :   void registerEHFrames() override {}
     309             : };
     310             : 
     311             : }
     312             : 
     313             : #endif

Generated by: LCOV version 1.13