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