1 //===-- RuntimeDyldMachO.cpp - Run-time dynamic linker for MC-JIT -*- 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 // Implementation of the MC-JIT runtime dynamic linker. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "RuntimeDyldMachO.h" 14 #include "Targets/RuntimeDyldMachOAArch64.h" 15 #include "Targets/RuntimeDyldMachOARM.h" 16 #include "Targets/RuntimeDyldMachOI386.h" 17 #include "Targets/RuntimeDyldMachOX86_64.h" 18 #include "llvm/ADT/STLExtras.h" 19 #include "llvm/ADT/StringRef.h" 20 21 using namespace llvm; 22 using namespace llvm::object; 23 24 #define DEBUG_TYPE "dyld" 25 26 namespace { 27 28 class LoadedMachOObjectInfo final 29 : public LoadedObjectInfoHelper<LoadedMachOObjectInfo, 30 RuntimeDyld::LoadedObjectInfo> { 31 public: 32 LoadedMachOObjectInfo(RuntimeDyldImpl &RTDyld, 33 ObjSectionToIDMap ObjSecToIDMap) 34 : LoadedObjectInfoHelper(RTDyld, std::move(ObjSecToIDMap)) {} 35 36 OwningBinary<ObjectFile> 37 getObjectForDebug(const ObjectFile &Obj) const override { 38 return OwningBinary<ObjectFile>(); 39 } 40 }; 41 42 } 43 44 namespace llvm { 45 46 int64_t RuntimeDyldMachO::memcpyAddend(const RelocationEntry &RE) const { 47 unsigned NumBytes = 1 << RE.Size; 48 uint8_t *Src = Sections[RE.SectionID].getAddress() + RE.Offset; 49 50 return static_cast<int64_t>(readBytesUnaligned(Src, NumBytes)); 51 } 52 53 Expected<relocation_iterator> 54 RuntimeDyldMachO::processScatteredVANILLA( 55 unsigned SectionID, relocation_iterator RelI, 56 const ObjectFile &BaseObjT, 57 RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID, 58 bool TargetIsLocalThumbFunc) { 59 const MachOObjectFile &Obj = 60 static_cast<const MachOObjectFile&>(BaseObjT); 61 MachO::any_relocation_info RE = 62 Obj.getRelocation(RelI->getRawDataRefImpl()); 63 64 SectionEntry &Section = Sections[SectionID]; 65 uint32_t RelocType = Obj.getAnyRelocationType(RE); 66 bool IsPCRel = Obj.getAnyRelocationPCRel(RE); 67 unsigned Size = Obj.getAnyRelocationLength(RE); 68 uint64_t Offset = RelI->getOffset(); 69 uint8_t *LocalAddress = Section.getAddressWithOffset(Offset); 70 unsigned NumBytes = 1 << Size; 71 int64_t Addend = readBytesUnaligned(LocalAddress, NumBytes); 72 73 unsigned SymbolBaseAddr = Obj.getScatteredRelocationValue(RE); 74 section_iterator TargetSI = getSectionByAddress(Obj, SymbolBaseAddr); 75 assert(TargetSI != Obj.section_end() && "Can't find section for symbol"); 76 uint64_t SectionBaseAddr = TargetSI->getAddress(); 77 SectionRef TargetSection = *TargetSI; 78 bool IsCode = TargetSection.isText(); 79 uint32_t TargetSectionID = ~0U; 80 if (auto TargetSectionIDOrErr = 81 findOrEmitSection(Obj, TargetSection, IsCode, ObjSectionToID)) 82 TargetSectionID = *TargetSectionIDOrErr; 83 else 84 return TargetSectionIDOrErr.takeError(); 85 86 Addend -= SectionBaseAddr; 87 RelocationEntry R(SectionID, Offset, RelocType, Addend, IsPCRel, Size); 88 R.IsTargetThumbFunc = TargetIsLocalThumbFunc; 89 90 addRelocationForSection(R, TargetSectionID); 91 92 return ++RelI; 93 } 94 95 96 Expected<RelocationValueRef> 97 RuntimeDyldMachO::getRelocationValueRef( 98 const ObjectFile &BaseTObj, const relocation_iterator &RI, 99 const RelocationEntry &RE, ObjSectionToIDMap &ObjSectionToID) { 100 101 const MachOObjectFile &Obj = 102 static_cast<const MachOObjectFile &>(BaseTObj); 103 MachO::any_relocation_info RelInfo = 104 Obj.getRelocation(RI->getRawDataRefImpl()); 105 RelocationValueRef Value; 106 107 bool IsExternal = Obj.getPlainRelocationExternal(RelInfo); 108 if (IsExternal) { 109 symbol_iterator Symbol = RI->getSymbol(); 110 StringRef TargetName; 111 if (auto TargetNameOrErr = Symbol->getName()) 112 TargetName = *TargetNameOrErr; 113 else 114 return TargetNameOrErr.takeError(); 115 RTDyldSymbolTable::const_iterator SI = 116 GlobalSymbolTable.find(TargetName.data()); 117 if (SI != GlobalSymbolTable.end()) { 118 const auto &SymInfo = SI->second; 119 Value.SectionID = SymInfo.getSectionID(); 120 Value.Offset = SymInfo.getOffset() + RE.Addend; 121 } else { 122 Value.SymbolName = TargetName.data(); 123 Value.Offset = RE.Addend; 124 } 125 } else { 126 SectionRef Sec = Obj.getAnyRelocationSection(RelInfo); 127 bool IsCode = Sec.isText(); 128 if (auto SectionIDOrErr = findOrEmitSection(Obj, Sec, IsCode, 129 ObjSectionToID)) 130 Value.SectionID = *SectionIDOrErr; 131 else 132 return SectionIDOrErr.takeError(); 133 uint64_t Addr = Sec.getAddress(); 134 Value.Offset = RE.Addend - Addr; 135 } 136 137 return Value; 138 } 139 140 void RuntimeDyldMachO::makeValueAddendPCRel(RelocationValueRef &Value, 141 const relocation_iterator &RI, 142 unsigned OffsetToNextPC) { 143 auto &O = *cast<MachOObjectFile>(RI->getObject()); 144 section_iterator SecI = O.getRelocationRelocatedSection(RI); 145 Value.Offset += RI->getOffset() + OffsetToNextPC + SecI->getAddress(); 146 } 147 148 void RuntimeDyldMachO::dumpRelocationToResolve(const RelocationEntry &RE, 149 uint64_t Value) const { 150 const SectionEntry &Section = Sections[RE.SectionID]; 151 uint8_t *LocalAddress = Section.getAddress() + RE.Offset; 152 uint64_t FinalAddress = Section.getLoadAddress() + RE.Offset; 153 154 dbgs() << "resolveRelocation Section: " << RE.SectionID 155 << " LocalAddress: " << format("%p", LocalAddress) 156 << " FinalAddress: " << format("0x%016" PRIx64, FinalAddress) 157 << " Value: " << format("0x%016" PRIx64, Value) << " Addend: " << RE.Addend 158 << " isPCRel: " << RE.IsPCRel << " MachoType: " << RE.RelType 159 << " Size: " << (1 << RE.Size) << "\n"; 160 } 161 162 section_iterator 163 RuntimeDyldMachO::getSectionByAddress(const MachOObjectFile &Obj, 164 uint64_t Addr) { 165 section_iterator SI = Obj.section_begin(); 166 section_iterator SE = Obj.section_end(); 167 168 for (; SI != SE; ++SI) { 169 uint64_t SAddr = SI->getAddress(); 170 uint64_t SSize = SI->getSize(); 171 if ((Addr >= SAddr) && (Addr < SAddr + SSize)) 172 return SI; 173 } 174 175 return SE; 176 } 177 178 179 // Populate __pointers section. 180 Error RuntimeDyldMachO::populateIndirectSymbolPointersSection( 181 const MachOObjectFile &Obj, 182 const SectionRef &PTSection, 183 unsigned PTSectionID) { 184 assert(!Obj.is64Bit() && 185 "Pointer table section not supported in 64-bit MachO."); 186 187 MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand(); 188 MachO::section Sec32 = Obj.getSection(PTSection.getRawDataRefImpl()); 189 uint32_t PTSectionSize = Sec32.size; 190 unsigned FirstIndirectSymbol = Sec32.reserved1; 191 const unsigned PTEntrySize = 4; 192 unsigned NumPTEntries = PTSectionSize / PTEntrySize; 193 unsigned PTEntryOffset = 0; 194 195 assert((PTSectionSize % PTEntrySize) == 0 && 196 "Pointers section does not contain a whole number of stubs?"); 197 198 LLVM_DEBUG(dbgs() << "Populating pointer table section " 199 << Sections[PTSectionID].getName() << ", Section ID " 200 << PTSectionID << ", " << NumPTEntries << " entries, " 201 << PTEntrySize << " bytes each:\n"); 202 203 for (unsigned i = 0; i < NumPTEntries; ++i) { 204 unsigned SymbolIndex = 205 Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i); 206 symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex); 207 StringRef IndirectSymbolName; 208 if (auto IndirectSymbolNameOrErr = SI->getName()) 209 IndirectSymbolName = *IndirectSymbolNameOrErr; 210 else 211 return IndirectSymbolNameOrErr.takeError(); 212 LLVM_DEBUG(dbgs() << " " << IndirectSymbolName << ": index " << SymbolIndex 213 << ", PT offset: " << PTEntryOffset << "\n"); 214 RelocationEntry RE(PTSectionID, PTEntryOffset, 215 MachO::GENERIC_RELOC_VANILLA, 0, false, 2); 216 addRelocationForSymbol(RE, IndirectSymbolName); 217 PTEntryOffset += PTEntrySize; 218 } 219 return Error::success(); 220 } 221 222 bool RuntimeDyldMachO::isCompatibleFile(const object::ObjectFile &Obj) const { 223 return Obj.isMachO(); 224 } 225 226 template <typename Impl> 227 Error 228 RuntimeDyldMachOCRTPBase<Impl>::finalizeLoad(const ObjectFile &Obj, 229 ObjSectionToIDMap &SectionMap) { 230 unsigned EHFrameSID = RTDYLD_INVALID_SECTION_ID; 231 unsigned TextSID = RTDYLD_INVALID_SECTION_ID; 232 unsigned ExceptTabSID = RTDYLD_INVALID_SECTION_ID; 233 234 for (const auto &Section : Obj.sections()) { 235 StringRef Name; 236 if (Expected<StringRef> NameOrErr = Section.getName()) 237 Name = *NameOrErr; 238 else 239 consumeError(NameOrErr.takeError()); 240 241 // Force emission of the __text, __eh_frame, and __gcc_except_tab sections 242 // if they're present. Otherwise call down to the impl to handle other 243 // sections that have already been emitted. 244 if (Name == "__text") { 245 if (auto TextSIDOrErr = findOrEmitSection(Obj, Section, true, SectionMap)) 246 TextSID = *TextSIDOrErr; 247 else 248 return TextSIDOrErr.takeError(); 249 } else if (Name == "__eh_frame") { 250 if (auto EHFrameSIDOrErr = findOrEmitSection(Obj, Section, false, 251 SectionMap)) 252 EHFrameSID = *EHFrameSIDOrErr; 253 else 254 return EHFrameSIDOrErr.takeError(); 255 } else if (Name == "__gcc_except_tab") { 256 if (auto ExceptTabSIDOrErr = findOrEmitSection(Obj, Section, true, 257 SectionMap)) 258 ExceptTabSID = *ExceptTabSIDOrErr; 259 else 260 return ExceptTabSIDOrErr.takeError(); 261 } else { 262 auto I = SectionMap.find(Section); 263 if (I != SectionMap.end()) 264 if (auto Err = impl().finalizeSection(Obj, I->second, Section)) 265 return Err; 266 } 267 } 268 UnregisteredEHFrameSections.push_back( 269 EHFrameRelatedSections(EHFrameSID, TextSID, ExceptTabSID)); 270 271 return Error::success(); 272 } 273 274 template <typename Impl> 275 unsigned char *RuntimeDyldMachOCRTPBase<Impl>::processFDE(uint8_t *P, 276 int64_t DeltaForText, 277 int64_t DeltaForEH) { 278 typedef typename Impl::TargetPtrT TargetPtrT; 279 280 LLVM_DEBUG(dbgs() << "Processing FDE: Delta for text: " << DeltaForText 281 << ", Delta for EH: " << DeltaForEH << "\n"); 282 uint32_t Length = readBytesUnaligned(P, 4); 283 P += 4; 284 uint8_t *Ret = P + Length; 285 uint32_t Offset = readBytesUnaligned(P, 4); 286 if (Offset == 0) // is a CIE 287 return Ret; 288 289 P += 4; 290 TargetPtrT FDELocation = readBytesUnaligned(P, sizeof(TargetPtrT)); 291 TargetPtrT NewLocation = FDELocation - DeltaForText; 292 writeBytesUnaligned(NewLocation, P, sizeof(TargetPtrT)); 293 294 P += sizeof(TargetPtrT); 295 296 // Skip the FDE address range 297 P += sizeof(TargetPtrT); 298 299 uint8_t Augmentationsize = *P; 300 P += 1; 301 if (Augmentationsize != 0) { 302 TargetPtrT LSDA = readBytesUnaligned(P, sizeof(TargetPtrT)); 303 TargetPtrT NewLSDA = LSDA - DeltaForEH; 304 writeBytesUnaligned(NewLSDA, P, sizeof(TargetPtrT)); 305 } 306 307 return Ret; 308 } 309 310 static int64_t computeDelta(SectionEntry *A, SectionEntry *B) { 311 int64_t ObjDistance = static_cast<int64_t>(A->getObjAddress()) - 312 static_cast<int64_t>(B->getObjAddress()); 313 int64_t MemDistance = A->getLoadAddress() - B->getLoadAddress(); 314 return ObjDistance - MemDistance; 315 } 316 317 template <typename Impl> 318 void RuntimeDyldMachOCRTPBase<Impl>::registerEHFrames() { 319 320 for (int i = 0, e = UnregisteredEHFrameSections.size(); i != e; ++i) { 321 EHFrameRelatedSections &SectionInfo = UnregisteredEHFrameSections[i]; 322 if (SectionInfo.EHFrameSID == RTDYLD_INVALID_SECTION_ID || 323 SectionInfo.TextSID == RTDYLD_INVALID_SECTION_ID) 324 continue; 325 SectionEntry *Text = &Sections[SectionInfo.TextSID]; 326 SectionEntry *EHFrame = &Sections[SectionInfo.EHFrameSID]; 327 SectionEntry *ExceptTab = nullptr; 328 if (SectionInfo.ExceptTabSID != RTDYLD_INVALID_SECTION_ID) 329 ExceptTab = &Sections[SectionInfo.ExceptTabSID]; 330 331 int64_t DeltaForText = computeDelta(Text, EHFrame); 332 int64_t DeltaForEH = 0; 333 if (ExceptTab) 334 DeltaForEH = computeDelta(ExceptTab, EHFrame); 335 336 uint8_t *P = EHFrame->getAddress(); 337 uint8_t *End = P + EHFrame->getSize(); 338 while (P != End) { 339 P = processFDE(P, DeltaForText, DeltaForEH); 340 } 341 342 MemMgr.registerEHFrames(EHFrame->getAddress(), EHFrame->getLoadAddress(), 343 EHFrame->getSize()); 344 } 345 UnregisteredEHFrameSections.clear(); 346 } 347 348 std::unique_ptr<RuntimeDyldMachO> 349 RuntimeDyldMachO::create(Triple::ArchType Arch, 350 RuntimeDyld::MemoryManager &MemMgr, 351 JITSymbolResolver &Resolver) { 352 switch (Arch) { 353 default: 354 llvm_unreachable("Unsupported target for RuntimeDyldMachO."); 355 break; 356 case Triple::arm: 357 return std::make_unique<RuntimeDyldMachOARM>(MemMgr, Resolver); 358 case Triple::aarch64: 359 return std::make_unique<RuntimeDyldMachOAArch64>(MemMgr, Resolver); 360 case Triple::aarch64_32: 361 return std::make_unique<RuntimeDyldMachOAArch64>(MemMgr, Resolver); 362 case Triple::x86: 363 return std::make_unique<RuntimeDyldMachOI386>(MemMgr, Resolver); 364 case Triple::x86_64: 365 return std::make_unique<RuntimeDyldMachOX86_64>(MemMgr, Resolver); 366 } 367 } 368 369 std::unique_ptr<RuntimeDyld::LoadedObjectInfo> 370 RuntimeDyldMachO::loadObject(const object::ObjectFile &O) { 371 if (auto ObjSectionToIDOrErr = loadObjectImpl(O)) 372 return std::make_unique<LoadedMachOObjectInfo>(*this, 373 *ObjSectionToIDOrErr); 374 else { 375 HasError = true; 376 raw_string_ostream ErrStream(ErrorStr); 377 logAllUnhandledErrors(ObjSectionToIDOrErr.takeError(), ErrStream); 378 return nullptr; 379 } 380 } 381 382 } // end namespace llvm 383