1303231Sdim//===--- RuntimeDyldCOFFThumb.h --- COFF/Thumb specific code ---*- C++ --*-===// 2303231Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6303231Sdim// 7303231Sdim//===----------------------------------------------------------------------===// 8303231Sdim// 9303231Sdim// COFF thumb support for MC-JIT runtime dynamic linker. 10303231Sdim// 11303231Sdim//===----------------------------------------------------------------------===// 12303231Sdim 13303231Sdim#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H 14303231Sdim#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H 15303231Sdim 16321369Sdim#include "../RuntimeDyldCOFF.h" 17321369Sdim#include "llvm/BinaryFormat/COFF.h" 18303231Sdim#include "llvm/Object/COFF.h" 19303231Sdim 20303231Sdim#define DEBUG_TYPE "dyld" 21303231Sdim 22303231Sdimnamespace llvm { 23303231Sdim 24353358Sdimstatic bool isThumbFunc(object::symbol_iterator Symbol, 25353358Sdim const object::ObjectFile &Obj, 26353358Sdim object::section_iterator Section) { 27353358Sdim Expected<object::SymbolRef::Type> SymTypeOrErr = Symbol->getType(); 28314564Sdim if (!SymTypeOrErr) { 29314564Sdim std::string Buf; 30314564Sdim raw_string_ostream OS(Buf); 31344779Sdim logAllUnhandledErrors(SymTypeOrErr.takeError(), OS); 32314564Sdim OS.flush(); 33314564Sdim report_fatal_error(Buf); 34314564Sdim } 35314564Sdim 36353358Sdim if (*SymTypeOrErr != object::SymbolRef::ST_Function) 37314564Sdim return false; 38314564Sdim 39314564Sdim // We check the IMAGE_SCN_MEM_16BIT flag in the section of the symbol to tell 40314564Sdim // if it's thumb or not 41353358Sdim return cast<object::COFFObjectFile>(Obj) 42353358Sdim .getCOFFSection(*Section) 43353358Sdim ->Characteristics & 44314564Sdim COFF::IMAGE_SCN_MEM_16BIT; 45314564Sdim} 46314564Sdim 47303231Sdimclass RuntimeDyldCOFFThumb : public RuntimeDyldCOFF { 48303231Sdimpublic: 49303231Sdim RuntimeDyldCOFFThumb(RuntimeDyld::MemoryManager &MM, 50314564Sdim JITSymbolResolver &Resolver) 51303231Sdim : RuntimeDyldCOFF(MM, Resolver) {} 52303231Sdim 53353358Sdim unsigned getMaxStubSize() const override { 54303231Sdim return 16; // 8-byte load instructions, 4-byte jump, 4-byte padding 55303231Sdim } 56303231Sdim 57303231Sdim unsigned getStubAlignment() override { return 1; } 58303231Sdim 59353358Sdim Expected<object::relocation_iterator> 60303231Sdim processRelocationRef(unsigned SectionID, 61353358Sdim object::relocation_iterator RelI, 62353358Sdim const object::ObjectFile &Obj, 63303231Sdim ObjSectionToIDMap &ObjSectionToID, 64303231Sdim StubMap &Stubs) override { 65303231Sdim auto Symbol = RelI->getSymbol(); 66303231Sdim if (Symbol == Obj.symbol_end()) 67303231Sdim report_fatal_error("Unknown symbol in relocation"); 68303231Sdim 69303231Sdim Expected<StringRef> TargetNameOrErr = Symbol->getName(); 70303231Sdim if (!TargetNameOrErr) 71303231Sdim return TargetNameOrErr.takeError(); 72303231Sdim StringRef TargetName = *TargetNameOrErr; 73303231Sdim 74303231Sdim auto SectionOrErr = Symbol->getSection(); 75303231Sdim if (!SectionOrErr) 76303231Sdim return SectionOrErr.takeError(); 77303231Sdim auto Section = *SectionOrErr; 78303231Sdim 79303231Sdim uint64_t RelType = RelI->getType(); 80303231Sdim uint64_t Offset = RelI->getOffset(); 81303231Sdim 82303231Sdim // Determine the Addend used to adjust the relocation value. 83303231Sdim uint64_t Addend = 0; 84303231Sdim SectionEntry &AddendSection = Sections[SectionID]; 85303231Sdim uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset; 86303231Sdim uint8_t *Displacement = (uint8_t *)ObjTarget; 87303231Sdim 88303231Sdim switch (RelType) { 89303231Sdim case COFF::IMAGE_REL_ARM_ADDR32: 90303231Sdim case COFF::IMAGE_REL_ARM_ADDR32NB: 91303231Sdim case COFF::IMAGE_REL_ARM_SECREL: 92303231Sdim Addend = readBytesUnaligned(Displacement, 4); 93303231Sdim break; 94303231Sdim default: 95303231Sdim break; 96303231Sdim } 97303231Sdim 98303231Sdim#if !defined(NDEBUG) 99303231Sdim SmallString<32> RelTypeName; 100303231Sdim RelI->getTypeName(RelTypeName); 101303231Sdim#endif 102341825Sdim LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset 103341825Sdim << " RelType: " << RelTypeName << " TargetName: " 104341825Sdim << TargetName << " Addend " << Addend << "\n"); 105303231Sdim 106303231Sdim unsigned TargetSectionID = -1; 107303231Sdim if (Section == Obj.section_end()) { 108303231Sdim RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0); 109303231Sdim addRelocationForSymbol(RE, TargetName); 110303231Sdim } else { 111303231Sdim if (auto TargetSectionIDOrErr = 112303231Sdim findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID)) 113303231Sdim TargetSectionID = *TargetSectionIDOrErr; 114303231Sdim else 115303231Sdim return TargetSectionIDOrErr.takeError(); 116303231Sdim 117314564Sdim // We need to find out if the relocation is relative to a thumb function 118314564Sdim // so that we include the ISA selection bit when resolve the relocation 119314564Sdim bool IsTargetThumbFunc = isThumbFunc(Symbol, Obj, Section); 120314564Sdim 121303231Sdim switch (RelType) { 122303231Sdim default: llvm_unreachable("unsupported relocation type"); 123303231Sdim case COFF::IMAGE_REL_ARM_ABSOLUTE: 124303231Sdim // This relocation is ignored. 125303231Sdim break; 126314564Sdim case COFF::IMAGE_REL_ARM_ADDR32: { 127314564Sdim RelocationEntry RE = RelocationEntry( 128314564Sdim SectionID, Offset, RelType, Addend, TargetSectionID, 129314564Sdim getSymbolOffset(*Symbol), 0, 0, false, 0, IsTargetThumbFunc); 130314564Sdim addRelocationForSection(RE, TargetSectionID); 131314564Sdim break; 132314564Sdim } 133303231Sdim case COFF::IMAGE_REL_ARM_ADDR32NB: { 134303231Sdim RelocationEntry RE = 135303231Sdim RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID, 136303231Sdim getSymbolOffset(*Symbol), 0, 0, false, 0); 137303231Sdim addRelocationForSection(RE, TargetSectionID); 138303231Sdim break; 139303231Sdim } 140303231Sdim case COFF::IMAGE_REL_ARM_SECTION: { 141303231Sdim RelocationEntry RE = 142303231Sdim RelocationEntry(TargetSectionID, Offset, RelType, 0); 143303231Sdim addRelocationForSection(RE, TargetSectionID); 144303231Sdim break; 145303231Sdim } 146303231Sdim case COFF::IMAGE_REL_ARM_SECREL: { 147303231Sdim RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType, 148303231Sdim getSymbolOffset(*Symbol) + Addend); 149303231Sdim addRelocationForSection(RE, TargetSectionID); 150303231Sdim break; 151303231Sdim } 152303231Sdim case COFF::IMAGE_REL_ARM_MOV32T: { 153314564Sdim RelocationEntry RE = RelocationEntry( 154314564Sdim SectionID, Offset, RelType, Addend, TargetSectionID, 155314564Sdim getSymbolOffset(*Symbol), 0, 0, false, 0, IsTargetThumbFunc); 156303231Sdim addRelocationForSection(RE, TargetSectionID); 157303231Sdim break; 158303231Sdim } 159303231Sdim case COFF::IMAGE_REL_ARM_BRANCH20T: 160303231Sdim case COFF::IMAGE_REL_ARM_BRANCH24T: 161303231Sdim case COFF::IMAGE_REL_ARM_BLX23T: { 162303231Sdim RelocationEntry RE = 163303231Sdim RelocationEntry(SectionID, Offset, RelType, 164303231Sdim getSymbolOffset(*Symbol) + Addend, true, 0); 165303231Sdim addRelocationForSection(RE, TargetSectionID); 166303231Sdim break; 167303231Sdim } 168303231Sdim } 169303231Sdim } 170303231Sdim 171303231Sdim return ++RelI; 172303231Sdim } 173303231Sdim 174303231Sdim void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { 175303231Sdim const auto Section = Sections[RE.SectionID]; 176303231Sdim uint8_t *Target = Section.getAddressWithOffset(RE.Offset); 177314564Sdim int ISASelectionBit = RE.IsTargetThumbFunc ? 1 : 0; 178303231Sdim 179303231Sdim switch (RE.RelType) { 180303231Sdim default: llvm_unreachable("unsupported relocation type"); 181303231Sdim case COFF::IMAGE_REL_ARM_ABSOLUTE: 182303231Sdim // This relocation is ignored. 183303231Sdim break; 184303231Sdim case COFF::IMAGE_REL_ARM_ADDR32: { 185303231Sdim // The target's 32-bit VA. 186303231Sdim uint64_t Result = 187303231Sdim RE.Sections.SectionA == static_cast<uint32_t>(-1) 188303231Sdim ? Value 189303231Sdim : Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend); 190314564Sdim Result |= ISASelectionBit; 191327952Sdim assert(Result <= UINT32_MAX && "relocation overflow"); 192341825Sdim LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 193341825Sdim << " RelType: IMAGE_REL_ARM_ADDR32" 194341825Sdim << " TargetSection: " << RE.Sections.SectionA 195341825Sdim << " Value: " << format("0x%08" PRIx32, Result) 196341825Sdim << '\n'); 197303231Sdim writeBytesUnaligned(Result, Target, 4); 198303231Sdim break; 199303231Sdim } 200303231Sdim case COFF::IMAGE_REL_ARM_ADDR32NB: { 201303231Sdim // The target's 32-bit RVA. 202303231Sdim // NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase 203303231Sdim uint64_t Result = Sections[RE.Sections.SectionA].getLoadAddress() - 204303231Sdim Sections[0].getLoadAddress() + RE.Addend; 205327952Sdim assert(Result <= UINT32_MAX && "relocation overflow"); 206341825Sdim LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 207341825Sdim << " RelType: IMAGE_REL_ARM_ADDR32NB" 208341825Sdim << " TargetSection: " << RE.Sections.SectionA 209341825Sdim << " Value: " << format("0x%08" PRIx32, Result) 210341825Sdim << '\n'); 211314564Sdim Result |= ISASelectionBit; 212303231Sdim writeBytesUnaligned(Result, Target, 4); 213303231Sdim break; 214303231Sdim } 215303231Sdim case COFF::IMAGE_REL_ARM_SECTION: 216303231Sdim // 16-bit section index of the section that contains the target. 217327952Sdim assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX && 218303231Sdim "relocation overflow"); 219341825Sdim LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 220341825Sdim << " RelType: IMAGE_REL_ARM_SECTION Value: " 221341825Sdim << RE.SectionID << '\n'); 222303231Sdim writeBytesUnaligned(RE.SectionID, Target, 2); 223303231Sdim break; 224303231Sdim case COFF::IMAGE_REL_ARM_SECREL: 225303231Sdim // 32-bit offset of the target from the beginning of its section. 226327952Sdim assert(static_cast<uint64_t>(RE.Addend) <= UINT32_MAX && 227303231Sdim "relocation overflow"); 228341825Sdim LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 229341825Sdim << " RelType: IMAGE_REL_ARM_SECREL Value: " << RE.Addend 230341825Sdim << '\n'); 231303231Sdim writeBytesUnaligned(RE.Addend, Target, 2); 232303231Sdim break; 233303231Sdim case COFF::IMAGE_REL_ARM_MOV32T: { 234303231Sdim // 32-bit VA of the target applied to a contiguous MOVW+MOVT pair. 235303231Sdim uint64_t Result = 236303231Sdim Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend); 237327952Sdim assert(Result <= UINT32_MAX && "relocation overflow"); 238341825Sdim LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 239341825Sdim << " RelType: IMAGE_REL_ARM_MOV32T" 240341825Sdim << " TargetSection: " << RE.Sections.SectionA 241341825Sdim << " Value: " << format("0x%08" PRIx32, Result) 242341825Sdim << '\n'); 243303231Sdim 244303231Sdim // MOVW(T3): |11110|i|10|0|1|0|0|imm4|0|imm3|Rd|imm8| 245303231Sdim // imm32 = zext imm4:i:imm3:imm8 246303231Sdim // MOVT(T1): |11110|i|10|1|1|0|0|imm4|0|imm3|Rd|imm8| 247303231Sdim // imm16 = imm4:i:imm3:imm8 248303231Sdim 249303231Sdim auto EncodeImmediate = [](uint8_t *Bytes, uint16_t Immediate) { 250303231Sdim Bytes[0] |= ((Immediate & 0xf000) >> 12); 251303231Sdim Bytes[1] |= ((Immediate & 0x0800) >> 11); 252303231Sdim Bytes[2] |= ((Immediate & 0x00ff) >> 0); 253314564Sdim Bytes[3] |= (((Immediate & 0x0700) >> 8) << 4); 254303231Sdim }; 255303231Sdim 256314564Sdim EncodeImmediate(&Target[0], 257314564Sdim (static_cast<uint32_t>(Result) >> 00) | ISASelectionBit); 258303231Sdim EncodeImmediate(&Target[4], static_cast<uint32_t>(Result) >> 16); 259303231Sdim 260303231Sdim break; 261303231Sdim } 262303231Sdim case COFF::IMAGE_REL_ARM_BRANCH20T: { 263303231Sdim // The most significant 20-bits of the signed 21-bit relative displacement 264303231Sdim uint64_t Value = 265303231Sdim RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4; 266327952Sdim assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX && 267303231Sdim "relocation overflow"); 268327952Sdim assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN && 269303231Sdim "relocation underflow"); 270341825Sdim LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 271341825Sdim << " RelType: IMAGE_REL_ARM_BRANCH20T" 272341825Sdim << " Value: " << static_cast<int32_t>(Value) << '\n'); 273303231Sdim static_cast<void>(Value); 274303231Sdim llvm_unreachable("unimplemented relocation"); 275303231Sdim break; 276303231Sdim } 277303231Sdim case COFF::IMAGE_REL_ARM_BRANCH24T: { 278303231Sdim // The most significant 24-bits of the signed 25-bit relative displacement 279303231Sdim uint64_t Value = 280303231Sdim RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4; 281327952Sdim assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX && 282303231Sdim "relocation overflow"); 283327952Sdim assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN && 284303231Sdim "relocation underflow"); 285341825Sdim LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 286341825Sdim << " RelType: IMAGE_REL_ARM_BRANCH24T" 287341825Sdim << " Value: " << static_cast<int32_t>(Value) << '\n'); 288303231Sdim static_cast<void>(Value); 289303231Sdim llvm_unreachable("unimplemented relocation"); 290303231Sdim break; 291303231Sdim } 292303231Sdim case COFF::IMAGE_REL_ARM_BLX23T: { 293303231Sdim // The most significant 24-bits of the signed 25-bit relative displacement 294303231Sdim uint64_t Value = 295303231Sdim RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4; 296327952Sdim assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX && 297303231Sdim "relocation overflow"); 298327952Sdim assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN && 299303231Sdim "relocation underflow"); 300341825Sdim LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 301341825Sdim << " RelType: IMAGE_REL_ARM_BLX23T" 302341825Sdim << " Value: " << static_cast<int32_t>(Value) << '\n'); 303303231Sdim static_cast<void>(Value); 304303231Sdim llvm_unreachable("unimplemented relocation"); 305303231Sdim break; 306303231Sdim } 307303231Sdim } 308303231Sdim } 309303231Sdim 310303231Sdim void registerEHFrames() override {} 311303231Sdim}; 312303231Sdim 313303231Sdim} 314303231Sdim 315303231Sdim#endif 316