1 //===--- RuntimeDyldCOFFI386.h --- COFF/X86_64 specific code ---*- C++ --*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // COFF x86 support for MC-JIT runtime dynamic linker. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFI386_H 14 #define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFI386_H 15 16 #include "../RuntimeDyldCOFF.h" 17 #include "llvm/BinaryFormat/COFF.h" 18 #include "llvm/Object/COFF.h" 19 20 #define DEBUG_TYPE "dyld" 21 22 namespace llvm { 23 24 class RuntimeDyldCOFFI386 : public RuntimeDyldCOFF { 25 public: 26 RuntimeDyldCOFFI386(RuntimeDyld::MemoryManager &MM, 27 JITSymbolResolver &Resolver) 28 : RuntimeDyldCOFF(MM, Resolver, 4, COFF::IMAGE_REL_I386_DIR32) {} 29 30 unsigned getMaxStubSize() const override { 31 return 8; // 2-byte jmp instruction + 32-bit relative address + 2 byte pad 32 } 33 34 Align getStubAlignment() override { return Align(1); } 35 36 Expected<object::relocation_iterator> 37 processRelocationRef(unsigned SectionID, 38 object::relocation_iterator RelI, 39 const object::ObjectFile &Obj, 40 ObjSectionToIDMap &ObjSectionToID, 41 StubMap &Stubs) override { 42 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 bool IsExtern = Section == Obj.section_end(); 57 58 uint64_t RelType = RelI->getType(); 59 uint64_t Offset = RelI->getOffset(); 60 61 unsigned TargetSectionID = -1; 62 uint64_t TargetOffset = -1; 63 if (TargetName.startswith(getImportSymbolPrefix())) { 64 TargetSectionID = SectionID; 65 TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName, true); 66 TargetName = StringRef(); 67 IsExtern = false; 68 } else if (!IsExtern) { 69 if (auto TargetSectionIDOrErr = findOrEmitSection( 70 Obj, *Section, Section->isText(), ObjSectionToID)) 71 TargetSectionID = *TargetSectionIDOrErr; 72 else 73 return TargetSectionIDOrErr.takeError(); 74 if (RelType != COFF::IMAGE_REL_I386_SECTION) 75 TargetOffset = getSymbolOffset(*Symbol); 76 } 77 78 // Determine the Addend used to adjust the relocation value. 79 uint64_t Addend = 0; 80 SectionEntry &AddendSection = Sections[SectionID]; 81 uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset; 82 uint8_t *Displacement = (uint8_t *)ObjTarget; 83 84 switch (RelType) { 85 case COFF::IMAGE_REL_I386_DIR32: 86 case COFF::IMAGE_REL_I386_DIR32NB: 87 case COFF::IMAGE_REL_I386_SECREL: 88 case COFF::IMAGE_REL_I386_REL32: { 89 Addend = readBytesUnaligned(Displacement, 4); 90 break; 91 } 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 if (IsExtern) { 105 RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0); 106 addRelocationForSymbol(RE, TargetName); 107 } else { 108 109 switch (RelType) { 110 case COFF::IMAGE_REL_I386_ABSOLUTE: 111 // This relocation is ignored. 112 break; 113 case COFF::IMAGE_REL_I386_DIR32: 114 case COFF::IMAGE_REL_I386_DIR32NB: 115 case COFF::IMAGE_REL_I386_REL32: { 116 RelocationEntry RE = 117 RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID, 118 TargetOffset, 0, 0, false, 0); 119 addRelocationForSection(RE, TargetSectionID); 120 break; 121 } 122 case COFF::IMAGE_REL_I386_SECTION: { 123 RelocationEntry RE = 124 RelocationEntry(TargetSectionID, Offset, RelType, 0); 125 addRelocationForSection(RE, TargetSectionID); 126 break; 127 } 128 case COFF::IMAGE_REL_I386_SECREL: { 129 RelocationEntry RE = 130 RelocationEntry(SectionID, Offset, RelType, TargetOffset + Addend); 131 addRelocationForSection(RE, TargetSectionID); 132 break; 133 } 134 default: 135 llvm_unreachable("unsupported relocation type"); 136 } 137 } 138 139 return ++RelI; 140 } 141 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 case COFF::IMAGE_REL_I386_ABSOLUTE: 148 // This relocation is ignored. 149 break; 150 case COFF::IMAGE_REL_I386_DIR32: { 151 // The target's 32-bit VA. 152 uint64_t Result = 153 RE.Sections.SectionA == static_cast<uint32_t>(-1) 154 ? Value 155 : Sections[RE.Sections.SectionA].getLoadAddressWithOffset( 156 RE.Addend); 157 assert(Result <= UINT32_MAX && "relocation overflow"); 158 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 159 << " RelType: IMAGE_REL_I386_DIR32" 160 << " TargetSection: " << RE.Sections.SectionA 161 << " Value: " << format("0x%08" PRIx32, Result) 162 << '\n'); 163 writeBytesUnaligned(Result, Target, 4); 164 break; 165 } 166 case COFF::IMAGE_REL_I386_DIR32NB: { 167 // The target's 32-bit RVA. 168 // NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase 169 uint64_t Result = 170 Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend) - 171 Sections[0].getLoadAddress(); 172 assert(Result <= UINT32_MAX && "relocation overflow"); 173 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 174 << " RelType: IMAGE_REL_I386_DIR32NB" 175 << " TargetSection: " << RE.Sections.SectionA 176 << " Value: " << format("0x%08" PRIx32, Result) 177 << '\n'); 178 writeBytesUnaligned(Result, Target, 4); 179 break; 180 } 181 case COFF::IMAGE_REL_I386_REL32: { 182 // 32-bit relative displacement to the target. 183 uint64_t Result = RE.Sections.SectionA == static_cast<uint32_t>(-1) 184 ? Value 185 : Sections[RE.Sections.SectionA].getLoadAddress(); 186 Result = Result - Section.getLoadAddress() + RE.Addend - 4 - RE.Offset; 187 assert(static_cast<int64_t>(Result) <= INT32_MAX && 188 "relocation overflow"); 189 assert(static_cast<int64_t>(Result) >= INT32_MIN && 190 "relocation underflow"); 191 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 192 << " RelType: IMAGE_REL_I386_REL32" 193 << " TargetSection: " << RE.Sections.SectionA 194 << " Value: " << format("0x%08" PRIx32, Result) 195 << '\n'); 196 writeBytesUnaligned(Result, Target, 4); 197 break; 198 } 199 case COFF::IMAGE_REL_I386_SECTION: 200 // 16-bit section index of the section that contains the target. 201 assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX && 202 "relocation overflow"); 203 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 204 << " RelType: IMAGE_REL_I386_SECTION Value: " 205 << RE.SectionID << '\n'); 206 writeBytesUnaligned(RE.SectionID, Target, 2); 207 break; 208 case COFF::IMAGE_REL_I386_SECREL: 209 // 32-bit offset of the target from the beginning of its section. 210 assert(static_cast<uint64_t>(RE.Addend) <= UINT32_MAX && 211 "relocation overflow"); 212 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset 213 << " RelType: IMAGE_REL_I386_SECREL Value: " 214 << RE.Addend << '\n'); 215 writeBytesUnaligned(RE.Addend, Target, 4); 216 break; 217 default: 218 llvm_unreachable("unsupported relocation type"); 219 } 220 } 221 222 void registerEHFrames() override {} 223 }; 224 225 } 226 227 #endif 228 229