1274955Ssvnmir//===---- RuntimeDyldMachOI386.h ---- MachO/I386 specific code. ---*- C++ -*-=// 2274955Ssvnmir// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6274955Ssvnmir// 7274955Ssvnmir//===----------------------------------------------------------------------===// 8274955Ssvnmir 9280031Sdim#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOI386_H 10280031Sdim#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOI386_H 11274955Ssvnmir 12274955Ssvnmir#include "../RuntimeDyldMachO.h" 13309124Sdim#include <string> 14274955Ssvnmir 15274955Ssvnmir#define DEBUG_TYPE "dyld" 16274955Ssvnmir 17274955Ssvnmirnamespace llvm { 18274955Ssvnmir 19274955Ssvnmirclass RuntimeDyldMachOI386 20274955Ssvnmir : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOI386> { 21274955Ssvnmirpublic: 22280031Sdim 23280031Sdim typedef uint32_t TargetPtrT; 24280031Sdim 25288943Sdim RuntimeDyldMachOI386(RuntimeDyld::MemoryManager &MM, 26314564Sdim JITSymbolResolver &Resolver) 27288943Sdim : RuntimeDyldMachOCRTPBase(MM, Resolver) {} 28274955Ssvnmir 29353358Sdim unsigned getMaxStubSize() const override { return 0; } 30274955Ssvnmir 31274955Ssvnmir unsigned getStubAlignment() override { return 1; } 32274955Ssvnmir 33309124Sdim Expected<relocation_iterator> 34274955Ssvnmir processRelocationRef(unsigned SectionID, relocation_iterator RelI, 35280031Sdim const ObjectFile &BaseObjT, 36280031Sdim ObjSectionToIDMap &ObjSectionToID, 37280031Sdim StubMap &Stubs) override { 38274955Ssvnmir const MachOObjectFile &Obj = 39280031Sdim static_cast<const MachOObjectFile &>(BaseObjT); 40274955Ssvnmir MachO::any_relocation_info RelInfo = 41274955Ssvnmir Obj.getRelocation(RelI->getRawDataRefImpl()); 42274955Ssvnmir uint32_t RelType = Obj.getAnyRelocationType(RelInfo); 43274955Ssvnmir 44274955Ssvnmir if (Obj.isRelocationScattered(RelInfo)) { 45274955Ssvnmir if (RelType == MachO::GENERIC_RELOC_SECTDIFF || 46274955Ssvnmir RelType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) 47280031Sdim return processSECTDIFFRelocation(SectionID, RelI, Obj, 48274955Ssvnmir ObjSectionToID); 49280031Sdim else if (RelType == MachO::GENERIC_RELOC_VANILLA) 50296417Sdim return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID); 51309124Sdim return make_error<RuntimeDyldError>(("Unhandled I386 scattered relocation " 52309124Sdim "type: " + Twine(RelType)).str()); 53274955Ssvnmir } 54274955Ssvnmir 55309124Sdim switch (RelType) { 56309124Sdim UNIMPLEMENTED_RELOC(MachO::GENERIC_RELOC_PAIR); 57309124Sdim UNIMPLEMENTED_RELOC(MachO::GENERIC_RELOC_PB_LA_PTR); 58309124Sdim UNIMPLEMENTED_RELOC(MachO::GENERIC_RELOC_TLV); 59309124Sdim default: 60309124Sdim if (RelType > MachO::GENERIC_RELOC_TLV) 61309124Sdim return make_error<RuntimeDyldError>(("MachO I386 relocation type " + 62309124Sdim Twine(RelType) + 63309124Sdim " is out of range").str()); 64309124Sdim break; 65309124Sdim } 66309124Sdim 67280031Sdim RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI)); 68280031Sdim RE.Addend = memcpyAddend(RE); 69309124Sdim RelocationValueRef Value; 70309124Sdim if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID)) 71309124Sdim Value = *ValueOrErr; 72309124Sdim else 73309124Sdim return ValueOrErr.takeError(); 74274955Ssvnmir 75274955Ssvnmir // Addends for external, PC-rel relocations on i386 point back to the zero 76274955Ssvnmir // offset. Calculate the final offset from the relocation target instead. 77274955Ssvnmir // This allows us to use the same logic for both external and internal 78274955Ssvnmir // relocations in resolveI386RelocationRef. 79274955Ssvnmir // bool IsExtern = Obj.getPlainRelocationExternal(RelInfo); 80274955Ssvnmir // if (IsExtern && RE.IsPCRel) { 81274955Ssvnmir // uint64_t RelocAddr = 0; 82274955Ssvnmir // RelI->getAddress(RelocAddr); 83274955Ssvnmir // Value.Addend += RelocAddr + 4; 84274955Ssvnmir // } 85274955Ssvnmir if (RE.IsPCRel) 86288943Sdim makeValueAddendPCRel(Value, RelI, 1 << RE.Size); 87274955Ssvnmir 88280031Sdim RE.Addend = Value.Offset; 89274955Ssvnmir 90274955Ssvnmir if (Value.SymbolName) 91274955Ssvnmir addRelocationForSymbol(RE, Value.SymbolName); 92274955Ssvnmir else 93274955Ssvnmir addRelocationForSection(RE, Value.SectionID); 94274955Ssvnmir 95274955Ssvnmir return ++RelI; 96274955Ssvnmir } 97274955Ssvnmir 98280031Sdim void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { 99341825Sdim LLVM_DEBUG(dumpRelocationToResolve(RE, Value)); 100274955Ssvnmir 101274955Ssvnmir const SectionEntry &Section = Sections[RE.SectionID]; 102296417Sdim uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset); 103274955Ssvnmir 104274955Ssvnmir if (RE.IsPCRel) { 105296417Sdim uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset); 106274955Ssvnmir Value -= FinalAddress + 4; // see MachOX86_64::resolveRelocation. 107274955Ssvnmir } 108274955Ssvnmir 109274955Ssvnmir switch (RE.RelType) { 110274955Ssvnmir case MachO::GENERIC_RELOC_VANILLA: 111280031Sdim writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size); 112274955Ssvnmir break; 113274955Ssvnmir case MachO::GENERIC_RELOC_SECTDIFF: 114274955Ssvnmir case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: { 115296417Sdim uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress(); 116296417Sdim uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress(); 117274955Ssvnmir assert((Value == SectionABase || Value == SectionBBase) && 118274955Ssvnmir "Unexpected SECTDIFF relocation value."); 119274955Ssvnmir Value = SectionABase - SectionBBase + RE.Addend; 120280031Sdim writeBytesUnaligned(Value, LocalAddress, 1 << RE.Size); 121274955Ssvnmir break; 122274955Ssvnmir } 123309124Sdim default: 124309124Sdim llvm_unreachable("Invalid relocation type!"); 125274955Ssvnmir } 126274955Ssvnmir } 127274955Ssvnmir 128309124Sdim Error finalizeSection(const ObjectFile &Obj, unsigned SectionID, 129274955Ssvnmir const SectionRef &Section) { 130274955Ssvnmir StringRef Name; 131360784Sdim if (Expected<StringRef> NameOrErr = Section.getName()) 132360784Sdim Name = *NameOrErr; 133360784Sdim else 134360784Sdim consumeError(NameOrErr.takeError()); 135274955Ssvnmir 136274955Ssvnmir if (Name == "__jump_table") 137309124Sdim return populateJumpTable(cast<MachOObjectFile>(Obj), Section, SectionID); 138274955Ssvnmir else if (Name == "__pointers") 139309124Sdim return populateIndirectSymbolPointersSection(cast<MachOObjectFile>(Obj), 140309124Sdim Section, SectionID); 141309124Sdim return Error::success(); 142274955Ssvnmir } 143274955Ssvnmir 144274955Ssvnmirprivate: 145309124Sdim Expected<relocation_iterator> 146274955Ssvnmir processSECTDIFFRelocation(unsigned SectionID, relocation_iterator RelI, 147280031Sdim const ObjectFile &BaseObjT, 148274955Ssvnmir ObjSectionToIDMap &ObjSectionToID) { 149280031Sdim const MachOObjectFile &Obj = 150280031Sdim static_cast<const MachOObjectFile&>(BaseObjT); 151274955Ssvnmir MachO::any_relocation_info RE = 152280031Sdim Obj.getRelocation(RelI->getRawDataRefImpl()); 153274955Ssvnmir 154274955Ssvnmir SectionEntry &Section = Sections[SectionID]; 155280031Sdim uint32_t RelocType = Obj.getAnyRelocationType(RE); 156280031Sdim bool IsPCRel = Obj.getAnyRelocationPCRel(RE); 157280031Sdim unsigned Size = Obj.getAnyRelocationLength(RE); 158288943Sdim uint64_t Offset = RelI->getOffset(); 159296417Sdim uint8_t *LocalAddress = Section.getAddressWithOffset(Offset); 160274955Ssvnmir unsigned NumBytes = 1 << Size; 161280031Sdim uint64_t Addend = readBytesUnaligned(LocalAddress, NumBytes); 162274955Ssvnmir 163274955Ssvnmir ++RelI; 164274955Ssvnmir MachO::any_relocation_info RE2 = 165280031Sdim Obj.getRelocation(RelI->getRawDataRefImpl()); 166274955Ssvnmir 167280031Sdim uint32_t AddrA = Obj.getScatteredRelocationValue(RE); 168280031Sdim section_iterator SAI = getSectionByAddress(Obj, AddrA); 169280031Sdim assert(SAI != Obj.section_end() && "Can't find section for address A"); 170280031Sdim uint64_t SectionABase = SAI->getAddress(); 171274955Ssvnmir uint64_t SectionAOffset = AddrA - SectionABase; 172274955Ssvnmir SectionRef SectionA = *SAI; 173280031Sdim bool IsCode = SectionA.isText(); 174309124Sdim uint32_t SectionAID = ~0U; 175309124Sdim if (auto SectionAIDOrErr = 176309124Sdim findOrEmitSection(Obj, SectionA, IsCode, ObjSectionToID)) 177309124Sdim SectionAID = *SectionAIDOrErr; 178309124Sdim else 179309124Sdim return SectionAIDOrErr.takeError(); 180274955Ssvnmir 181280031Sdim uint32_t AddrB = Obj.getScatteredRelocationValue(RE2); 182280031Sdim section_iterator SBI = getSectionByAddress(Obj, AddrB); 183280031Sdim assert(SBI != Obj.section_end() && "Can't find section for address B"); 184280031Sdim uint64_t SectionBBase = SBI->getAddress(); 185274955Ssvnmir uint64_t SectionBOffset = AddrB - SectionBBase; 186274955Ssvnmir SectionRef SectionB = *SBI; 187309124Sdim uint32_t SectionBID = ~0U; 188309124Sdim if (auto SectionBIDOrErr = 189309124Sdim findOrEmitSection(Obj, SectionB, IsCode, ObjSectionToID)) 190309124Sdim SectionBID = *SectionBIDOrErr; 191309124Sdim else 192309124Sdim return SectionBIDOrErr.takeError(); 193274955Ssvnmir 194288943Sdim // Compute the addend 'C' from the original expression 'A - B + C'. 195288943Sdim Addend -= AddrA - AddrB; 196274955Ssvnmir 197341825Sdim LLVM_DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA 198341825Sdim << ", AddrB: " << AddrB << ", Addend: " << Addend 199341825Sdim << ", SectionA ID: " << SectionAID << ", SectionAOffset: " 200341825Sdim << SectionAOffset << ", SectionB ID: " << SectionBID 201341825Sdim << ", SectionBOffset: " << SectionBOffset << "\n"); 202288943Sdim RelocationEntry R(SectionID, Offset, RelocType, Addend, SectionAID, 203288943Sdim SectionAOffset, SectionBID, SectionBOffset, 204288943Sdim IsPCRel, Size); 205274955Ssvnmir 206274955Ssvnmir addRelocationForSection(R, SectionAID); 207274955Ssvnmir 208274955Ssvnmir return ++RelI; 209274955Ssvnmir } 210274955Ssvnmir 211274955Ssvnmir // Populate stubs in __jump_table section. 212309124Sdim Error populateJumpTable(const MachOObjectFile &Obj, 213309124Sdim const SectionRef &JTSection, 214274955Ssvnmir unsigned JTSectionID) { 215274955Ssvnmir MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand(); 216274955Ssvnmir MachO::section Sec32 = Obj.getSection(JTSection.getRawDataRefImpl()); 217274955Ssvnmir uint32_t JTSectionSize = Sec32.size; 218274955Ssvnmir unsigned FirstIndirectSymbol = Sec32.reserved1; 219274955Ssvnmir unsigned JTEntrySize = Sec32.reserved2; 220274955Ssvnmir unsigned NumJTEntries = JTSectionSize / JTEntrySize; 221274955Ssvnmir uint8_t *JTSectionAddr = getSectionAddress(JTSectionID); 222274955Ssvnmir unsigned JTEntryOffset = 0; 223274955Ssvnmir 224309124Sdim if (JTSectionSize % JTEntrySize != 0) 225309124Sdim return make_error<RuntimeDyldError>("Jump-table section does not contain " 226309124Sdim "a whole number of stubs?"); 227274955Ssvnmir 228274955Ssvnmir for (unsigned i = 0; i < NumJTEntries; ++i) { 229274955Ssvnmir unsigned SymbolIndex = 230274955Ssvnmir Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i); 231274955Ssvnmir symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex); 232309124Sdim Expected<StringRef> IndirectSymbolName = SI->getName(); 233309124Sdim if (!IndirectSymbolName) 234309124Sdim return IndirectSymbolName.takeError(); 235274955Ssvnmir uint8_t *JTEntryAddr = JTSectionAddr + JTEntryOffset; 236274955Ssvnmir createStubFunction(JTEntryAddr); 237274955Ssvnmir RelocationEntry RE(JTSectionID, JTEntryOffset + 1, 238274955Ssvnmir MachO::GENERIC_RELOC_VANILLA, 0, true, 2); 239288943Sdim addRelocationForSymbol(RE, *IndirectSymbolName); 240274955Ssvnmir JTEntryOffset += JTEntrySize; 241274955Ssvnmir } 242309124Sdim 243309124Sdim return Error::success(); 244274955Ssvnmir } 245274955Ssvnmir 246274955Ssvnmir}; 247274955Ssvnmir} 248274955Ssvnmir 249274955Ssvnmir#undef DEBUG_TYPE 250274955Ssvnmir 251280031Sdim#endif 252