RuntimeDyldCOFFThumb.h revision 327952
1303231Sdim//===--- RuntimeDyldCOFFThumb.h --- COFF/Thumb specific code ---*- C++ --*-===// 2303231Sdim// 3303231Sdim// The LLVM Compiler Infrastructure 4303231Sdim// 5303231Sdim// This file is distributed under the University of Illinois Open Source 6303231Sdim// License. See LICENSE.TXT for details. 7303231Sdim// 8303231Sdim//===----------------------------------------------------------------------===// 9303231Sdim// 10303231Sdim// COFF thumb support for MC-JIT runtime dynamic linker. 11303231Sdim// 12303231Sdim//===----------------------------------------------------------------------===// 13303231Sdim 14303231Sdim#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H 15303231Sdim#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H 16303231Sdim 17321369Sdim#include "../RuntimeDyldCOFF.h" 18321369Sdim#include "llvm/BinaryFormat/COFF.h" 19303231Sdim#include "llvm/Object/COFF.h" 20303231Sdim 21303231Sdim#define DEBUG_TYPE "dyld" 22303231Sdim 23303231Sdimnamespace llvm { 24303231Sdim 25314564Sdimstatic bool isThumbFunc(symbol_iterator Symbol, const ObjectFile &Obj, 26314564Sdim section_iterator Section) { 27314564Sdim Expected<SymbolRef::Type> SymTypeOrErr = Symbol->getType(); 28314564Sdim if (!SymTypeOrErr) { 29314564Sdim std::string Buf; 30314564Sdim raw_string_ostream OS(Buf); 31314564Sdim logAllUnhandledErrors(SymTypeOrErr.takeError(), OS, ""); 32314564Sdim OS.flush(); 33314564Sdim report_fatal_error(Buf); 34314564Sdim } 35314564Sdim 36314564Sdim if (*SymTypeOrErr != 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 41314564Sdim return cast<COFFObjectFile>(Obj).getCOFFSection(*Section)->Characteristics & 42314564Sdim COFF::IMAGE_SCN_MEM_16BIT; 43314564Sdim} 44314564Sdim 45303231Sdimclass RuntimeDyldCOFFThumb : public RuntimeDyldCOFF { 46303231Sdimpublic: 47303231Sdim RuntimeDyldCOFFThumb(RuntimeDyld::MemoryManager &MM, 48314564Sdim JITSymbolResolver &Resolver) 49303231Sdim : RuntimeDyldCOFF(MM, Resolver) {} 50303231Sdim 51303231Sdim unsigned getMaxStubSize() override { 52303231Sdim return 16; // 8-byte load instructions, 4-byte jump, 4-byte padding 53303231Sdim } 54303231Sdim 55303231Sdim unsigned getStubAlignment() override { return 1; } 56303231Sdim 57303231Sdim Expected<relocation_iterator> 58303231Sdim processRelocationRef(unsigned SectionID, 59303231Sdim relocation_iterator RelI, 60303231Sdim const ObjectFile &Obj, 61303231Sdim ObjSectionToIDMap &ObjSectionToID, 62303231Sdim StubMap &Stubs) override { 63303231Sdim auto Symbol = RelI->getSymbol(); 64303231Sdim if (Symbol == Obj.symbol_end()) 65303231Sdim report_fatal_error("Unknown symbol in relocation"); 66303231Sdim 67303231Sdim Expected<StringRef> TargetNameOrErr = Symbol->getName(); 68303231Sdim if (!TargetNameOrErr) 69303231Sdim return TargetNameOrErr.takeError(); 70303231Sdim StringRef TargetName = *TargetNameOrErr; 71303231Sdim 72303231Sdim auto SectionOrErr = Symbol->getSection(); 73303231Sdim if (!SectionOrErr) 74303231Sdim return SectionOrErr.takeError(); 75303231Sdim auto Section = *SectionOrErr; 76303231Sdim 77303231Sdim uint64_t RelType = RelI->getType(); 78303231Sdim uint64_t Offset = RelI->getOffset(); 79303231Sdim 80303231Sdim // Determine the Addend used to adjust the relocation value. 81303231Sdim uint64_t Addend = 0; 82303231Sdim SectionEntry &AddendSection = Sections[SectionID]; 83303231Sdim uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset; 84303231Sdim uint8_t *Displacement = (uint8_t *)ObjTarget; 85303231Sdim 86303231Sdim switch (RelType) { 87303231Sdim case COFF::IMAGE_REL_ARM_ADDR32: 88303231Sdim case COFF::IMAGE_REL_ARM_ADDR32NB: 89303231Sdim case COFF::IMAGE_REL_ARM_SECREL: 90303231Sdim Addend = readBytesUnaligned(Displacement, 4); 91303231Sdim break; 92303231Sdim default: 93303231Sdim break; 94303231Sdim } 95303231Sdim 96303231Sdim#if !defined(NDEBUG) 97303231Sdim SmallString<32> RelTypeName; 98303231Sdim RelI->getTypeName(RelTypeName); 99303231Sdim#endif 100303231Sdim DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset 101303231Sdim << " RelType: " << RelTypeName << " TargetName: " << TargetName 102303231Sdim << " Addend " << Addend << "\n"); 103303231Sdim 104303231Sdim unsigned TargetSectionID = -1; 105303231Sdim if (Section == Obj.section_end()) { 106303231Sdim RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0); 107303231Sdim addRelocationForSymbol(RE, TargetName); 108303231Sdim } else { 109303231Sdim if (auto TargetSectionIDOrErr = 110303231Sdim findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID)) 111303231Sdim TargetSectionID = *TargetSectionIDOrErr; 112303231Sdim else 113303231Sdim return TargetSectionIDOrErr.takeError(); 114303231Sdim 115314564Sdim // We need to find out if the relocation is relative to a thumb function 116314564Sdim // so that we include the ISA selection bit when resolve the relocation 117314564Sdim bool IsTargetThumbFunc = isThumbFunc(Symbol, Obj, Section); 118314564Sdim 119303231Sdim switch (RelType) { 120303231Sdim default: llvm_unreachable("unsupported relocation type"); 121303231Sdim case COFF::IMAGE_REL_ARM_ABSOLUTE: 122303231Sdim // This relocation is ignored. 123303231Sdim break; 124314564Sdim case COFF::IMAGE_REL_ARM_ADDR32: { 125314564Sdim RelocationEntry RE = RelocationEntry( 126314564Sdim SectionID, Offset, RelType, Addend, TargetSectionID, 127314564Sdim getSymbolOffset(*Symbol), 0, 0, false, 0, IsTargetThumbFunc); 128314564Sdim addRelocationForSection(RE, TargetSectionID); 129314564Sdim break; 130314564Sdim } 131303231Sdim case COFF::IMAGE_REL_ARM_ADDR32NB: { 132303231Sdim RelocationEntry RE = 133303231Sdim RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID, 134303231Sdim getSymbolOffset(*Symbol), 0, 0, false, 0); 135303231Sdim addRelocationForSection(RE, TargetSectionID); 136303231Sdim break; 137303231Sdim } 138303231Sdim case COFF::IMAGE_REL_ARM_SECTION: { 139303231Sdim RelocationEntry RE = 140303231Sdim RelocationEntry(TargetSectionID, Offset, RelType, 0); 141303231Sdim addRelocationForSection(RE, TargetSectionID); 142303231Sdim break; 143303231Sdim } 144303231Sdim case COFF::IMAGE_REL_ARM_SECREL: { 145303231Sdim RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType, 146303231Sdim getSymbolOffset(*Symbol) + Addend); 147303231Sdim addRelocationForSection(RE, TargetSectionID); 148303231Sdim break; 149303231Sdim } 150303231Sdim case COFF::IMAGE_REL_ARM_MOV32T: { 151314564Sdim RelocationEntry RE = RelocationEntry( 152314564Sdim SectionID, Offset, RelType, Addend, TargetSectionID, 153314564Sdim getSymbolOffset(*Symbol), 0, 0, false, 0, IsTargetThumbFunc); 154303231Sdim addRelocationForSection(RE, TargetSectionID); 155303231Sdim break; 156303231Sdim } 157303231Sdim case COFF::IMAGE_REL_ARM_BRANCH20T: 158303231Sdim case COFF::IMAGE_REL_ARM_BRANCH24T: 159303231Sdim case COFF::IMAGE_REL_ARM_BLX23T: { 160303231Sdim RelocationEntry RE = 161303231Sdim RelocationEntry(SectionID, Offset, RelType, 162303231Sdim getSymbolOffset(*Symbol) + Addend, true, 0); 163303231Sdim addRelocationForSection(RE, TargetSectionID); 164303231Sdim break; 165303231Sdim } 166303231Sdim } 167303231Sdim } 168303231Sdim 169303231Sdim return ++RelI; 170303231Sdim } 171303231Sdim 172303231Sdim void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { 173303231Sdim const auto Section = Sections[RE.SectionID]; 174303231Sdim uint8_t *Target = Section.getAddressWithOffset(RE.Offset); 175314564Sdim int ISASelectionBit = RE.IsTargetThumbFunc ? 1 : 0; 176303231Sdim 177303231Sdim switch (RE.RelType) { 178303231Sdim default: llvm_unreachable("unsupported relocation type"); 179303231Sdim case COFF::IMAGE_REL_ARM_ABSOLUTE: 180303231Sdim // This relocation is ignored. 181303231Sdim break; 182303231Sdim case COFF::IMAGE_REL_ARM_ADDR32: { 183303231Sdim // The target's 32-bit VA. 184303231Sdim uint64_t Result = 185303231Sdim RE.Sections.SectionA == static_cast<uint32_t>(-1) 186303231Sdim ? Value 187303231Sdim : Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend); 188314564Sdim Result |= ISASelectionBit; 189327952Sdim assert(Result <= UINT32_MAX && "relocation overflow"); 190303231Sdim DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 191303231Sdim << " RelType: IMAGE_REL_ARM_ADDR32" 192303231Sdim << " TargetSection: " << RE.Sections.SectionA 193303231Sdim << " Value: " << format("0x%08" PRIx32, Result) << '\n'); 194303231Sdim writeBytesUnaligned(Result, Target, 4); 195303231Sdim break; 196303231Sdim } 197303231Sdim case COFF::IMAGE_REL_ARM_ADDR32NB: { 198303231Sdim // The target's 32-bit RVA. 199303231Sdim // NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase 200303231Sdim uint64_t Result = Sections[RE.Sections.SectionA].getLoadAddress() - 201303231Sdim Sections[0].getLoadAddress() + RE.Addend; 202327952Sdim assert(Result <= UINT32_MAX && "relocation overflow"); 203303231Sdim DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 204303231Sdim << " RelType: IMAGE_REL_ARM_ADDR32NB" 205303231Sdim << " TargetSection: " << RE.Sections.SectionA 206303231Sdim << " Value: " << format("0x%08" PRIx32, Result) << '\n'); 207314564Sdim Result |= ISASelectionBit; 208303231Sdim writeBytesUnaligned(Result, Target, 4); 209303231Sdim break; 210303231Sdim } 211303231Sdim case COFF::IMAGE_REL_ARM_SECTION: 212303231Sdim // 16-bit section index of the section that contains the target. 213327952Sdim assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX && 214303231Sdim "relocation overflow"); 215303231Sdim DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 216303231Sdim << " RelType: IMAGE_REL_ARM_SECTION Value: " << RE.SectionID 217303231Sdim << '\n'); 218303231Sdim writeBytesUnaligned(RE.SectionID, Target, 2); 219303231Sdim break; 220303231Sdim case COFF::IMAGE_REL_ARM_SECREL: 221303231Sdim // 32-bit offset of the target from the beginning of its section. 222327952Sdim assert(static_cast<uint64_t>(RE.Addend) <= UINT32_MAX && 223303231Sdim "relocation overflow"); 224303231Sdim DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 225303231Sdim << " RelType: IMAGE_REL_ARM_SECREL Value: " << RE.Addend 226303231Sdim << '\n'); 227303231Sdim writeBytesUnaligned(RE.Addend, Target, 2); 228303231Sdim break; 229303231Sdim case COFF::IMAGE_REL_ARM_MOV32T: { 230303231Sdim // 32-bit VA of the target applied to a contiguous MOVW+MOVT pair. 231303231Sdim uint64_t Result = 232303231Sdim Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend); 233327952Sdim assert(Result <= UINT32_MAX && "relocation overflow"); 234303231Sdim DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 235303231Sdim << " RelType: IMAGE_REL_ARM_MOV32T" 236303231Sdim << " TargetSection: " << RE.Sections.SectionA 237303231Sdim << " Value: " << format("0x%08" PRIx32, Result) << '\n'); 238303231Sdim 239303231Sdim // MOVW(T3): |11110|i|10|0|1|0|0|imm4|0|imm3|Rd|imm8| 240303231Sdim // imm32 = zext imm4:i:imm3:imm8 241303231Sdim // MOVT(T1): |11110|i|10|1|1|0|0|imm4|0|imm3|Rd|imm8| 242303231Sdim // imm16 = imm4:i:imm3:imm8 243303231Sdim 244303231Sdim auto EncodeImmediate = [](uint8_t *Bytes, uint16_t Immediate) { 245303231Sdim Bytes[0] |= ((Immediate & 0xf000) >> 12); 246303231Sdim Bytes[1] |= ((Immediate & 0x0800) >> 11); 247303231Sdim Bytes[2] |= ((Immediate & 0x00ff) >> 0); 248314564Sdim Bytes[3] |= (((Immediate & 0x0700) >> 8) << 4); 249303231Sdim }; 250303231Sdim 251314564Sdim EncodeImmediate(&Target[0], 252314564Sdim (static_cast<uint32_t>(Result) >> 00) | ISASelectionBit); 253303231Sdim EncodeImmediate(&Target[4], static_cast<uint32_t>(Result) >> 16); 254303231Sdim 255303231Sdim break; 256303231Sdim } 257303231Sdim case COFF::IMAGE_REL_ARM_BRANCH20T: { 258303231Sdim // The most significant 20-bits of the signed 21-bit relative displacement 259303231Sdim uint64_t Value = 260303231Sdim RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4; 261327952Sdim assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX && 262303231Sdim "relocation overflow"); 263327952Sdim assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN && 264303231Sdim "relocation underflow"); 265303231Sdim DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 266303231Sdim << " RelType: IMAGE_REL_ARM_BRANCH20T" 267303231Sdim << " Value: " << static_cast<int32_t>(Value) << '\n'); 268303231Sdim static_cast<void>(Value); 269303231Sdim llvm_unreachable("unimplemented relocation"); 270303231Sdim break; 271303231Sdim } 272303231Sdim case COFF::IMAGE_REL_ARM_BRANCH24T: { 273303231Sdim // The most significant 24-bits of the signed 25-bit relative displacement 274303231Sdim uint64_t Value = 275303231Sdim RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4; 276327952Sdim assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX && 277303231Sdim "relocation overflow"); 278327952Sdim assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN && 279303231Sdim "relocation underflow"); 280303231Sdim DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 281303231Sdim << " RelType: IMAGE_REL_ARM_BRANCH24T" 282303231Sdim << " Value: " << static_cast<int32_t>(Value) << '\n'); 283303231Sdim static_cast<void>(Value); 284303231Sdim llvm_unreachable("unimplemented relocation"); 285303231Sdim break; 286303231Sdim } 287303231Sdim case COFF::IMAGE_REL_ARM_BLX23T: { 288303231Sdim // The most significant 24-bits of the signed 25-bit relative displacement 289303231Sdim uint64_t Value = 290303231Sdim RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4; 291327952Sdim assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX && 292303231Sdim "relocation overflow"); 293327952Sdim assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN && 294303231Sdim "relocation underflow"); 295303231Sdim DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 296303231Sdim << " RelType: IMAGE_REL_ARM_BLX23T" 297303231Sdim << " Value: " << static_cast<int32_t>(Value) << '\n'); 298303231Sdim static_cast<void>(Value); 299303231Sdim llvm_unreachable("unimplemented relocation"); 300303231Sdim break; 301303231Sdim } 302303231Sdim } 303303231Sdim } 304303231Sdim 305303231Sdim void registerEHFrames() override {} 306303231Sdim}; 307303231Sdim 308303231Sdim} 309303231Sdim 310303231Sdim#endif 311