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