xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFThumb.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===--- RuntimeDyldCOFFThumb.h --- COFF/Thumb specific code ---*- C++ --*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // COFF thumb support for MC-JIT runtime dynamic linker.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H
140b57cec5SDimitry Andric #define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "../RuntimeDyldCOFF.h"
1706c3fb27SDimitry Andric #include "llvm/ADT/SmallString.h"
180b57cec5SDimitry Andric #include "llvm/BinaryFormat/COFF.h"
190b57cec5SDimitry Andric #include "llvm/Object/COFF.h"
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric #define DEBUG_TYPE "dyld"
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric namespace llvm {
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric static bool isThumbFunc(object::symbol_iterator Symbol,
260b57cec5SDimitry Andric                         const object::ObjectFile &Obj,
270b57cec5SDimitry Andric                         object::section_iterator Section) {
280b57cec5SDimitry Andric   Expected<object::SymbolRef::Type> SymTypeOrErr = Symbol->getType();
290b57cec5SDimitry Andric   if (!SymTypeOrErr) {
300b57cec5SDimitry Andric     std::string Buf;
310b57cec5SDimitry Andric     raw_string_ostream OS(Buf);
320b57cec5SDimitry Andric     logAllUnhandledErrors(SymTypeOrErr.takeError(), OS);
33349cc55cSDimitry Andric     report_fatal_error(Twine(OS.str()));
340b57cec5SDimitry Andric   }
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric   if (*SymTypeOrErr != object::SymbolRef::ST_Function)
370b57cec5SDimitry Andric     return false;
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric   // We check the IMAGE_SCN_MEM_16BIT flag in the section of the symbol to tell
400b57cec5SDimitry Andric   // if it's thumb or not
410b57cec5SDimitry Andric   return cast<object::COFFObjectFile>(Obj)
420b57cec5SDimitry Andric              .getCOFFSection(*Section)
430b57cec5SDimitry Andric              ->Characteristics &
440b57cec5SDimitry Andric          COFF::IMAGE_SCN_MEM_16BIT;
450b57cec5SDimitry Andric }
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric class RuntimeDyldCOFFThumb : public RuntimeDyldCOFF {
480b57cec5SDimitry Andric public:
490b57cec5SDimitry Andric   RuntimeDyldCOFFThumb(RuntimeDyld::MemoryManager &MM,
500b57cec5SDimitry Andric                        JITSymbolResolver &Resolver)
515ffd83dbSDimitry Andric       : RuntimeDyldCOFF(MM, Resolver, 4, COFF::IMAGE_REL_ARM_ADDR32) {}
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric   unsigned getMaxStubSize() const override {
540b57cec5SDimitry Andric     return 16; // 8-byte load instructions, 4-byte jump, 4-byte padding
550b57cec5SDimitry Andric   }
560b57cec5SDimitry Andric 
57*5f757f3fSDimitry Andric   Expected<JITSymbolFlags> getJITSymbolFlags(const SymbolRef &SR) override {
58*5f757f3fSDimitry Andric 
59*5f757f3fSDimitry Andric     auto Flags = RuntimeDyldImpl::getJITSymbolFlags(SR);
60*5f757f3fSDimitry Andric 
61*5f757f3fSDimitry Andric     if (!Flags) {
62*5f757f3fSDimitry Andric       return Flags.takeError();
63*5f757f3fSDimitry Andric     }
64*5f757f3fSDimitry Andric     auto SectionIterOrErr = SR.getSection();
65*5f757f3fSDimitry Andric     if (!SectionIterOrErr) {
66*5f757f3fSDimitry Andric       return SectionIterOrErr.takeError();
67*5f757f3fSDimitry Andric     }
68*5f757f3fSDimitry Andric     SectionRef Sec = *SectionIterOrErr.get();
69*5f757f3fSDimitry Andric     const object::COFFObjectFile *COFFObjPtr =
70*5f757f3fSDimitry Andric         cast<object::COFFObjectFile>(Sec.getObject());
71*5f757f3fSDimitry Andric     const coff_section *CoffSec = COFFObjPtr->getCOFFSection(Sec);
72*5f757f3fSDimitry Andric     bool isThumb = CoffSec->Characteristics & COFF::IMAGE_SCN_MEM_16BIT;
73*5f757f3fSDimitry Andric 
74*5f757f3fSDimitry Andric     Flags->getTargetFlags() = isThumb;
75*5f757f3fSDimitry Andric 
76*5f757f3fSDimitry Andric     return Flags;
77*5f757f3fSDimitry Andric   }
78*5f757f3fSDimitry Andric 
79bdd1243dSDimitry Andric   Align getStubAlignment() override { return Align(1); }
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric   Expected<object::relocation_iterator>
820b57cec5SDimitry Andric   processRelocationRef(unsigned SectionID,
830b57cec5SDimitry Andric                        object::relocation_iterator RelI,
840b57cec5SDimitry Andric                        const object::ObjectFile &Obj,
850b57cec5SDimitry Andric                        ObjSectionToIDMap &ObjSectionToID,
860b57cec5SDimitry Andric                        StubMap &Stubs) override {
870b57cec5SDimitry Andric     auto Symbol = RelI->getSymbol();
880b57cec5SDimitry Andric     if (Symbol == Obj.symbol_end())
890b57cec5SDimitry Andric       report_fatal_error("Unknown symbol in relocation");
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric     Expected<StringRef> TargetNameOrErr = Symbol->getName();
920b57cec5SDimitry Andric     if (!TargetNameOrErr)
930b57cec5SDimitry Andric       return TargetNameOrErr.takeError();
940b57cec5SDimitry Andric     StringRef TargetName = *TargetNameOrErr;
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric     auto SectionOrErr = Symbol->getSection();
970b57cec5SDimitry Andric     if (!SectionOrErr)
980b57cec5SDimitry Andric       return SectionOrErr.takeError();
990b57cec5SDimitry Andric     auto Section = *SectionOrErr;
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric     uint64_t RelType = RelI->getType();
1020b57cec5SDimitry Andric     uint64_t Offset = RelI->getOffset();
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric     // Determine the Addend used to adjust the relocation value.
1050b57cec5SDimitry Andric     uint64_t Addend = 0;
1060b57cec5SDimitry Andric     SectionEntry &AddendSection = Sections[SectionID];
1070b57cec5SDimitry Andric     uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset;
1080b57cec5SDimitry Andric     uint8_t *Displacement = (uint8_t *)ObjTarget;
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric     switch (RelType) {
1110b57cec5SDimitry Andric     case COFF::IMAGE_REL_ARM_ADDR32:
1120b57cec5SDimitry Andric     case COFF::IMAGE_REL_ARM_ADDR32NB:
1130b57cec5SDimitry Andric     case COFF::IMAGE_REL_ARM_SECREL:
1140b57cec5SDimitry Andric       Addend = readBytesUnaligned(Displacement, 4);
1150b57cec5SDimitry Andric       break;
1160b57cec5SDimitry Andric     default:
1170b57cec5SDimitry Andric       break;
1180b57cec5SDimitry Andric     }
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric #if !defined(NDEBUG)
1210b57cec5SDimitry Andric     SmallString<32> RelTypeName;
1220b57cec5SDimitry Andric     RelI->getTypeName(RelTypeName);
1230b57cec5SDimitry Andric #endif
1240b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
1250b57cec5SDimitry Andric                       << " RelType: " << RelTypeName << " TargetName: "
1260b57cec5SDimitry Andric                       << TargetName << " Addend " << Addend << "\n");
1270b57cec5SDimitry Andric 
1285ffd83dbSDimitry Andric     bool IsExtern = Section == Obj.section_end();
1290b57cec5SDimitry Andric     unsigned TargetSectionID = -1;
1305ffd83dbSDimitry Andric     uint64_t TargetOffset = -1;
1315ffd83dbSDimitry Andric 
132*5f757f3fSDimitry Andric     if (TargetName.starts_with(getImportSymbolPrefix())) {
1335ffd83dbSDimitry Andric       TargetSectionID = SectionID;
1345ffd83dbSDimitry Andric       TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName, true);
1355ffd83dbSDimitry Andric       TargetName = StringRef();
1365ffd83dbSDimitry Andric       IsExtern = false;
1375ffd83dbSDimitry Andric     } else if (!IsExtern) {
1380b57cec5SDimitry Andric       if (auto TargetSectionIDOrErr =
1390b57cec5SDimitry Andric           findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID))
1400b57cec5SDimitry Andric         TargetSectionID = *TargetSectionIDOrErr;
1410b57cec5SDimitry Andric       else
1420b57cec5SDimitry Andric         return TargetSectionIDOrErr.takeError();
1435ffd83dbSDimitry Andric       if (RelType != COFF::IMAGE_REL_ARM_SECTION)
1445ffd83dbSDimitry Andric         TargetOffset = getSymbolOffset(*Symbol);
1455ffd83dbSDimitry Andric     }
1465ffd83dbSDimitry Andric 
1475ffd83dbSDimitry Andric     if (IsExtern) {
1485ffd83dbSDimitry Andric       RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0);
1495ffd83dbSDimitry Andric       addRelocationForSymbol(RE, TargetName);
1505ffd83dbSDimitry Andric     } else {
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric       // We need to find out if the relocation is relative to a thumb function
1530b57cec5SDimitry Andric       // so that we include the ISA selection bit when resolve the relocation
1540b57cec5SDimitry Andric       bool IsTargetThumbFunc = isThumbFunc(Symbol, Obj, Section);
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric       switch (RelType) {
1570b57cec5SDimitry Andric       default: llvm_unreachable("unsupported relocation type");
1580b57cec5SDimitry Andric       case COFF::IMAGE_REL_ARM_ABSOLUTE:
1590b57cec5SDimitry Andric         // This relocation is ignored.
1600b57cec5SDimitry Andric         break;
1610b57cec5SDimitry Andric       case COFF::IMAGE_REL_ARM_ADDR32: {
1625ffd83dbSDimitry Andric         RelocationEntry RE =
1635ffd83dbSDimitry Andric             RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
1645ffd83dbSDimitry Andric                             TargetOffset, 0, 0, false, 0, IsTargetThumbFunc);
1650b57cec5SDimitry Andric         addRelocationForSection(RE, TargetSectionID);
1660b57cec5SDimitry Andric         break;
1670b57cec5SDimitry Andric       }
1680b57cec5SDimitry Andric       case COFF::IMAGE_REL_ARM_ADDR32NB: {
1690b57cec5SDimitry Andric         RelocationEntry RE =
1700b57cec5SDimitry Andric             RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
1715ffd83dbSDimitry Andric                             TargetOffset, 0, 0, false, 0);
1720b57cec5SDimitry Andric         addRelocationForSection(RE, TargetSectionID);
1730b57cec5SDimitry Andric         break;
1740b57cec5SDimitry Andric       }
1750b57cec5SDimitry Andric       case COFF::IMAGE_REL_ARM_SECTION: {
1760b57cec5SDimitry Andric         RelocationEntry RE =
1770b57cec5SDimitry Andric             RelocationEntry(TargetSectionID, Offset, RelType, 0);
1780b57cec5SDimitry Andric         addRelocationForSection(RE, TargetSectionID);
1790b57cec5SDimitry Andric         break;
1800b57cec5SDimitry Andric       }
1810b57cec5SDimitry Andric       case COFF::IMAGE_REL_ARM_SECREL: {
1825ffd83dbSDimitry Andric         RelocationEntry RE =
1835ffd83dbSDimitry Andric             RelocationEntry(SectionID, Offset, RelType, TargetOffset + Addend);
1840b57cec5SDimitry Andric         addRelocationForSection(RE, TargetSectionID);
1850b57cec5SDimitry Andric         break;
1860b57cec5SDimitry Andric       }
1870b57cec5SDimitry Andric       case COFF::IMAGE_REL_ARM_MOV32T: {
1885ffd83dbSDimitry Andric         RelocationEntry RE =
1895ffd83dbSDimitry Andric             RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
1905ffd83dbSDimitry Andric                             TargetOffset, 0, 0, false, 0, IsTargetThumbFunc);
1910b57cec5SDimitry Andric         addRelocationForSection(RE, TargetSectionID);
1920b57cec5SDimitry Andric         break;
1930b57cec5SDimitry Andric       }
1940b57cec5SDimitry Andric       case COFF::IMAGE_REL_ARM_BRANCH20T:
1950b57cec5SDimitry Andric       case COFF::IMAGE_REL_ARM_BRANCH24T:
1960b57cec5SDimitry Andric       case COFF::IMAGE_REL_ARM_BLX23T: {
1975ffd83dbSDimitry Andric         RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType,
1985ffd83dbSDimitry Andric                                              TargetOffset + Addend, true, 0);
1990b57cec5SDimitry Andric         addRelocationForSection(RE, TargetSectionID);
2000b57cec5SDimitry Andric         break;
2010b57cec5SDimitry Andric       }
2020b57cec5SDimitry Andric       }
2030b57cec5SDimitry Andric     }
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric     return ++RelI;
2060b57cec5SDimitry Andric   }
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric   void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
2090b57cec5SDimitry Andric     const auto Section = Sections[RE.SectionID];
2100b57cec5SDimitry Andric     uint8_t *Target = Section.getAddressWithOffset(RE.Offset);
2110b57cec5SDimitry Andric     int ISASelectionBit = RE.IsTargetThumbFunc ? 1 : 0;
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric     switch (RE.RelType) {
2140b57cec5SDimitry Andric     default: llvm_unreachable("unsupported relocation type");
2150b57cec5SDimitry Andric     case COFF::IMAGE_REL_ARM_ABSOLUTE:
2160b57cec5SDimitry Andric       // This relocation is ignored.
2170b57cec5SDimitry Andric       break;
2180b57cec5SDimitry Andric     case COFF::IMAGE_REL_ARM_ADDR32: {
2190b57cec5SDimitry Andric       // The target's 32-bit VA.
2200b57cec5SDimitry Andric       uint64_t Result =
2210b57cec5SDimitry Andric           RE.Sections.SectionA == static_cast<uint32_t>(-1)
2220b57cec5SDimitry Andric               ? Value
2230b57cec5SDimitry Andric               : Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);
2240b57cec5SDimitry Andric       Result |= ISASelectionBit;
2250b57cec5SDimitry Andric       assert(Result <= UINT32_MAX && "relocation overflow");
2260b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
2270b57cec5SDimitry Andric                         << " RelType: IMAGE_REL_ARM_ADDR32"
2280b57cec5SDimitry Andric                         << " TargetSection: " << RE.Sections.SectionA
2290b57cec5SDimitry Andric                         << " Value: " << format("0x%08" PRIx32, Result)
2300b57cec5SDimitry Andric                         << '\n');
2310b57cec5SDimitry Andric       writeBytesUnaligned(Result, Target, 4);
2320b57cec5SDimitry Andric       break;
2330b57cec5SDimitry Andric     }
2340b57cec5SDimitry Andric     case COFF::IMAGE_REL_ARM_ADDR32NB: {
2350b57cec5SDimitry Andric       // The target's 32-bit RVA.
2360b57cec5SDimitry Andric       // NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase
2370b57cec5SDimitry Andric       uint64_t Result = Sections[RE.Sections.SectionA].getLoadAddress() -
2380b57cec5SDimitry Andric                         Sections[0].getLoadAddress() + RE.Addend;
2390b57cec5SDimitry Andric       assert(Result <= UINT32_MAX && "relocation overflow");
2400b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
2410b57cec5SDimitry Andric                         << " RelType: IMAGE_REL_ARM_ADDR32NB"
2420b57cec5SDimitry Andric                         << " TargetSection: " << RE.Sections.SectionA
2430b57cec5SDimitry Andric                         << " Value: " << format("0x%08" PRIx32, Result)
2440b57cec5SDimitry Andric                         << '\n');
2450b57cec5SDimitry Andric       Result |= ISASelectionBit;
2460b57cec5SDimitry Andric       writeBytesUnaligned(Result, Target, 4);
2470b57cec5SDimitry Andric       break;
2480b57cec5SDimitry Andric     }
2490b57cec5SDimitry Andric     case COFF::IMAGE_REL_ARM_SECTION:
2500b57cec5SDimitry Andric       // 16-bit section index of the section that contains the target.
2510b57cec5SDimitry Andric       assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX &&
2520b57cec5SDimitry Andric              "relocation overflow");
2530b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
2540b57cec5SDimitry Andric                         << " RelType: IMAGE_REL_ARM_SECTION Value: "
2550b57cec5SDimitry Andric                         << RE.SectionID << '\n');
2560b57cec5SDimitry Andric       writeBytesUnaligned(RE.SectionID, Target, 2);
2570b57cec5SDimitry Andric       break;
2580b57cec5SDimitry Andric     case COFF::IMAGE_REL_ARM_SECREL:
2590b57cec5SDimitry Andric       // 32-bit offset of the target from the beginning of its section.
2600b57cec5SDimitry Andric       assert(static_cast<uint64_t>(RE.Addend) <= UINT32_MAX &&
2610b57cec5SDimitry Andric              "relocation overflow");
2620b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
2630b57cec5SDimitry Andric                         << " RelType: IMAGE_REL_ARM_SECREL Value: " << RE.Addend
2640b57cec5SDimitry Andric                         << '\n');
2650b57cec5SDimitry Andric       writeBytesUnaligned(RE.Addend, Target, 2);
2660b57cec5SDimitry Andric       break;
2670b57cec5SDimitry Andric     case COFF::IMAGE_REL_ARM_MOV32T: {
2680b57cec5SDimitry Andric       // 32-bit VA of the target applied to a contiguous MOVW+MOVT pair.
2690b57cec5SDimitry Andric       uint64_t Result =
2700b57cec5SDimitry Andric           Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);
2710b57cec5SDimitry Andric       assert(Result <= UINT32_MAX && "relocation overflow");
2720b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
2730b57cec5SDimitry Andric                         << " RelType: IMAGE_REL_ARM_MOV32T"
2740b57cec5SDimitry Andric                         << " TargetSection: " << RE.Sections.SectionA
2750b57cec5SDimitry Andric                         << " Value: " << format("0x%08" PRIx32, Result)
2760b57cec5SDimitry Andric                         << '\n');
2770b57cec5SDimitry Andric 
2780b57cec5SDimitry Andric       // MOVW(T3): |11110|i|10|0|1|0|0|imm4|0|imm3|Rd|imm8|
2790b57cec5SDimitry Andric       //            imm32 = zext imm4:i:imm3:imm8
2800b57cec5SDimitry Andric       // MOVT(T1): |11110|i|10|1|1|0|0|imm4|0|imm3|Rd|imm8|
2810b57cec5SDimitry Andric       //            imm16 =      imm4:i:imm3:imm8
2820b57cec5SDimitry Andric 
2830b57cec5SDimitry Andric       auto EncodeImmediate = [](uint8_t *Bytes, uint16_t Immediate)  {
2840b57cec5SDimitry Andric         Bytes[0] |= ((Immediate & 0xf000) >> 12);
2850b57cec5SDimitry Andric         Bytes[1] |= ((Immediate & 0x0800) >> 11);
2860b57cec5SDimitry Andric         Bytes[2] |= ((Immediate & 0x00ff) >>  0);
2870b57cec5SDimitry Andric         Bytes[3] |= (((Immediate & 0x0700) >>  8) << 4);
2880b57cec5SDimitry Andric       };
2890b57cec5SDimitry Andric 
2900b57cec5SDimitry Andric       EncodeImmediate(&Target[0],
2910b57cec5SDimitry Andric                       (static_cast<uint32_t>(Result) >> 00) | ISASelectionBit);
2920b57cec5SDimitry Andric       EncodeImmediate(&Target[4], static_cast<uint32_t>(Result) >> 16);
2930b57cec5SDimitry Andric       break;
2940b57cec5SDimitry Andric     }
2950b57cec5SDimitry Andric     case COFF::IMAGE_REL_ARM_BRANCH20T: {
2960b57cec5SDimitry Andric       // The most significant 20-bits of the signed 21-bit relative displacement
2970b57cec5SDimitry Andric       uint64_t Value =
2980b57cec5SDimitry Andric           RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
2990b57cec5SDimitry Andric       assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&
3000b57cec5SDimitry Andric              "relocation overflow");
3010b57cec5SDimitry Andric       assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&
3020b57cec5SDimitry Andric              "relocation underflow");
3030b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
3040b57cec5SDimitry Andric                         << " RelType: IMAGE_REL_ARM_BRANCH20T"
3050b57cec5SDimitry Andric                         << " Value: " << static_cast<int32_t>(Value) << '\n');
3060b57cec5SDimitry Andric       static_cast<void>(Value);
3070b57cec5SDimitry Andric       llvm_unreachable("unimplemented relocation");
3080b57cec5SDimitry Andric       break;
3090b57cec5SDimitry Andric     }
3100b57cec5SDimitry Andric     case COFF::IMAGE_REL_ARM_BRANCH24T: {
3110b57cec5SDimitry Andric       // The most significant 24-bits of the signed 25-bit relative displacement
3120b57cec5SDimitry Andric       uint64_t Value =
3130b57cec5SDimitry Andric           RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
3140b57cec5SDimitry Andric       assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&
3150b57cec5SDimitry Andric              "relocation overflow");
3160b57cec5SDimitry Andric       assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&
3170b57cec5SDimitry Andric              "relocation underflow");
3180b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
3190b57cec5SDimitry Andric                         << " RelType: IMAGE_REL_ARM_BRANCH24T"
3200b57cec5SDimitry Andric                         << " Value: " << static_cast<int32_t>(Value) << '\n');
3210b57cec5SDimitry Andric       static_cast<void>(Value);
3220b57cec5SDimitry Andric       llvm_unreachable("unimplemented relocation");
3230b57cec5SDimitry Andric       break;
3240b57cec5SDimitry Andric     }
3250b57cec5SDimitry Andric     case COFF::IMAGE_REL_ARM_BLX23T: {
3260b57cec5SDimitry Andric       // The most significant 24-bits of the signed 25-bit relative displacement
3270b57cec5SDimitry Andric       uint64_t Value =
3280b57cec5SDimitry Andric           RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
3290b57cec5SDimitry Andric       assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&
3300b57cec5SDimitry Andric              "relocation overflow");
3310b57cec5SDimitry Andric       assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&
3320b57cec5SDimitry Andric              "relocation underflow");
3330b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
3340b57cec5SDimitry Andric                         << " RelType: IMAGE_REL_ARM_BLX23T"
3350b57cec5SDimitry Andric                         << " Value: " << static_cast<int32_t>(Value) << '\n');
3360b57cec5SDimitry Andric       static_cast<void>(Value);
3370b57cec5SDimitry Andric       llvm_unreachable("unimplemented relocation");
3380b57cec5SDimitry Andric       break;
3390b57cec5SDimitry Andric     }
3400b57cec5SDimitry Andric     }
3410b57cec5SDimitry Andric   }
3420b57cec5SDimitry Andric 
3430b57cec5SDimitry Andric   void registerEHFrames() override {}
3440b57cec5SDimitry Andric };
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric }
3470b57cec5SDimitry Andric 
3480b57cec5SDimitry Andric #endif
349