RuntimeDyldMachO.cpp revision 261991
1234353Sdim//===-- RuntimeDyldMachO.cpp - Run-time dynamic linker for MC-JIT -*- C++ -*-=// 2224133Sdim// 3224133Sdim// The LLVM Compiler Infrastructure 4224133Sdim// 5224133Sdim// This file is distributed under the University of Illinois Open Source 6224133Sdim// License. See LICENSE.TXT for details. 7224133Sdim// 8224133Sdim//===----------------------------------------------------------------------===// 9224133Sdim// 10224133Sdim// Implementation of the MC-JIT runtime dynamic linker. 11224133Sdim// 12224133Sdim//===----------------------------------------------------------------------===// 13224133Sdim 14224133Sdim#define DEBUG_TYPE "dyld" 15249423Sdim#include "RuntimeDyldMachO.h" 16224133Sdim#include "llvm/ADT/OwningPtr.h" 17249423Sdim#include "llvm/ADT/STLExtras.h" 18224133Sdim#include "llvm/ADT/StringRef.h" 19224133Sdimusing namespace llvm; 20224133Sdimusing namespace llvm::object; 21224133Sdim 22224133Sdimnamespace llvm { 23224133Sdim 24251662Sdimstatic unsigned char *processFDE(unsigned char *P, intptr_t DeltaForText, intptr_t DeltaForEH) { 25251662Sdim uint32_t Length = *((uint32_t*)P); 26251662Sdim P += 4; 27251662Sdim unsigned char *Ret = P + Length; 28251662Sdim uint32_t Offset = *((uint32_t*)P); 29251662Sdim if (Offset == 0) // is a CIE 30251662Sdim return Ret; 31251662Sdim 32251662Sdim P += 4; 33251662Sdim intptr_t FDELocation = *((intptr_t*)P); 34251662Sdim intptr_t NewLocation = FDELocation - DeltaForText; 35251662Sdim *((intptr_t*)P) = NewLocation; 36251662Sdim P += sizeof(intptr_t); 37251662Sdim 38251662Sdim // Skip the FDE address range 39251662Sdim P += sizeof(intptr_t); 40251662Sdim 41251662Sdim uint8_t Augmentationsize = *P; 42251662Sdim P += 1; 43251662Sdim if (Augmentationsize != 0) { 44251662Sdim intptr_t LSDA = *((intptr_t*)P); 45251662Sdim intptr_t NewLSDA = LSDA - DeltaForEH; 46251662Sdim *((intptr_t*)P) = NewLSDA; 47251662Sdim } 48251662Sdim 49251662Sdim return Ret; 50251662Sdim} 51251662Sdim 52251662Sdimstatic intptr_t computeDelta(SectionEntry *A, SectionEntry *B) { 53251662Sdim intptr_t ObjDistance = A->ObjAddress - B->ObjAddress; 54251662Sdim intptr_t MemDistance = A->LoadAddress - B->LoadAddress; 55251662Sdim return ObjDistance - MemDistance; 56251662Sdim} 57251662Sdim 58261991Sdimvoid RuntimeDyldMachO::registerEHFrames() { 59251662Sdim 60261991Sdim if (!MemMgr) 61261991Sdim return; 62261991Sdim for (int i = 0, e = UnregisteredEHFrameSections.size(); i != e; ++i) { 63261991Sdim EHFrameRelatedSections &SectionInfo = UnregisteredEHFrameSections[i]; 64261991Sdim if (SectionInfo.EHFrameSID == RTDYLD_INVALID_SECTION_ID || 65261991Sdim SectionInfo.TextSID == RTDYLD_INVALID_SECTION_ID) 66261991Sdim continue; 67261991Sdim SectionEntry *Text = &Sections[SectionInfo.TextSID]; 68261991Sdim SectionEntry *EHFrame = &Sections[SectionInfo.EHFrameSID]; 69261991Sdim SectionEntry *ExceptTab = NULL; 70261991Sdim if (SectionInfo.ExceptTabSID != RTDYLD_INVALID_SECTION_ID) 71261991Sdim ExceptTab = &Sections[SectionInfo.ExceptTabSID]; 72251662Sdim 73261991Sdim intptr_t DeltaForText = computeDelta(Text, EHFrame); 74261991Sdim intptr_t DeltaForEH = 0; 75261991Sdim if (ExceptTab) 76261991Sdim DeltaForEH = computeDelta(ExceptTab, EHFrame); 77251662Sdim 78261991Sdim unsigned char *P = EHFrame->Address; 79261991Sdim unsigned char *End = P + EHFrame->Size; 80261991Sdim do { 81261991Sdim P = processFDE(P, DeltaForText, DeltaForEH); 82261991Sdim } while(P != End); 83261991Sdim 84261991Sdim MemMgr->registerEHFrames(EHFrame->Address, 85261991Sdim EHFrame->LoadAddress, 86261991Sdim EHFrame->Size); 87261991Sdim } 88261991Sdim UnregisteredEHFrameSections.clear(); 89251662Sdim} 90251662Sdim 91261991Sdimvoid RuntimeDyldMachO::finalizeLoad(ObjSectionToIDMap &SectionMap) { 92261991Sdim unsigned EHFrameSID = RTDYLD_INVALID_SECTION_ID; 93261991Sdim unsigned TextSID = RTDYLD_INVALID_SECTION_ID; 94261991Sdim unsigned ExceptTabSID = RTDYLD_INVALID_SECTION_ID; 95261991Sdim ObjSectionToIDMap::iterator i, e; 96261991Sdim for (i = SectionMap.begin(), e = SectionMap.end(); i != e; ++i) { 97261991Sdim const SectionRef &Section = i->first; 98261991Sdim StringRef Name; 99261991Sdim Section.getName(Name); 100261991Sdim if (Name == "__eh_frame") 101261991Sdim EHFrameSID = i->second; 102261991Sdim else if (Name == "__text") 103261991Sdim TextSID = i->second; 104261991Sdim else if (Name == "__gcc_except_tab") 105261991Sdim ExceptTabSID = i->second; 106261991Sdim } 107261991Sdim UnregisteredEHFrameSections.push_back(EHFrameRelatedSections(EHFrameSID, 108261991Sdim TextSID, 109261991Sdim ExceptTabSID)); 110261991Sdim} 111261991Sdim 112261991Sdim// The target location for the relocation is described by RE.SectionID and 113261991Sdim// RE.Offset. RE.SectionID can be used to find the SectionEntry. Each 114261991Sdim// SectionEntry has three members describing its location. 115261991Sdim// SectionEntry::Address is the address at which the section has been loaded 116261991Sdim// into memory in the current (host) process. SectionEntry::LoadAddress is the 117261991Sdim// address that the section will have in the target process. 118261991Sdim// SectionEntry::ObjAddress is the address of the bits for this section in the 119261991Sdim// original emitted object image (also in the current address space). 120261991Sdim// 121261991Sdim// Relocations will be applied as if the section were loaded at 122261991Sdim// SectionEntry::LoadAddress, but they will be applied at an address based 123261991Sdim// on SectionEntry::Address. SectionEntry::ObjAddress will be used to refer to 124261991Sdim// Target memory contents if they are required for value calculations. 125261991Sdim// 126261991Sdim// The Value parameter here is the load address of the symbol for the 127261991Sdim// relocation to be applied. For relocations which refer to symbols in the 128261991Sdim// current object Value will be the LoadAddress of the section in which 129261991Sdim// the symbol resides (RE.Addend provides additional information about the 130261991Sdim// symbol location). For external symbols, Value will be the address of the 131261991Sdim// symbol in the target address space. 132251662Sdimvoid RuntimeDyldMachO::resolveRelocation(const RelocationEntry &RE, 133251662Sdim uint64_t Value) { 134251662Sdim const SectionEntry &Section = Sections[RE.SectionID]; 135251662Sdim return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend, 136251662Sdim RE.IsPCRel, RE.Size); 137251662Sdim} 138251662Sdim 139243830Sdimvoid RuntimeDyldMachO::resolveRelocation(const SectionEntry &Section, 140243830Sdim uint64_t Offset, 141234353Sdim uint64_t Value, 142234353Sdim uint32_t Type, 143251662Sdim int64_t Addend, 144251662Sdim bool isPCRel, 145251662Sdim unsigned LogSize) { 146243830Sdim uint8_t *LocalAddress = Section.Address + Offset; 147243830Sdim uint64_t FinalAddress = Section.LoadAddress + Offset; 148251662Sdim unsigned MachoType = Type; 149251662Sdim unsigned Size = 1 << LogSize; 150234353Sdim 151239462Sdim DEBUG(dbgs() << "resolveRelocation LocalAddress: " 152239462Sdim << format("%p", LocalAddress) 153234353Sdim << " FinalAddress: " << format("%p", FinalAddress) 154234353Sdim << " Value: " << format("%p", Value) 155234353Sdim << " Addend: " << Addend 156234353Sdim << " isPCRel: " << isPCRel 157234353Sdim << " MachoType: " << MachoType 158234353Sdim << " Size: " << Size 159234353Sdim << "\n"); 160234353Sdim 161224133Sdim // This just dispatches to the proper target specific routine. 162234353Sdim switch (Arch) { 163234353Sdim default: llvm_unreachable("Unsupported CPU type!"); 164234353Sdim case Triple::x86_64: 165234353Sdim resolveX86_64Relocation(LocalAddress, 166234353Sdim FinalAddress, 167234353Sdim (uintptr_t)Value, 168234353Sdim isPCRel, 169234353Sdim MachoType, 170234353Sdim Size, 171234353Sdim Addend); 172234353Sdim break; 173234353Sdim case Triple::x86: 174234353Sdim resolveI386Relocation(LocalAddress, 175239462Sdim FinalAddress, 176239462Sdim (uintptr_t)Value, 177239462Sdim isPCRel, 178243830Sdim MachoType, 179239462Sdim Size, 180239462Sdim Addend); 181234353Sdim break; 182234353Sdim case Triple::arm: // Fall through. 183234353Sdim case Triple::thumb: 184234353Sdim resolveARMRelocation(LocalAddress, 185234353Sdim FinalAddress, 186234353Sdim (uintptr_t)Value, 187234353Sdim isPCRel, 188234353Sdim MachoType, 189234353Sdim Size, 190234353Sdim Addend); 191234353Sdim break; 192224133Sdim } 193224133Sdim} 194224133Sdim 195239462Sdimbool RuntimeDyldMachO::resolveI386Relocation(uint8_t *LocalAddress, 196239462Sdim uint64_t FinalAddress, 197239462Sdim uint64_t Value, 198239462Sdim bool isPCRel, 199239462Sdim unsigned Type, 200239462Sdim unsigned Size, 201239462Sdim int64_t Addend) { 202234353Sdim if (isPCRel) 203234353Sdim Value -= FinalAddress + 4; // see resolveX86_64Relocation 204234353Sdim 205234353Sdim switch (Type) { 206234353Sdim default: 207234353Sdim llvm_unreachable("Invalid relocation type!"); 208261991Sdim case MachO::GENERIC_RELOC_VANILLA: { 209234353Sdim uint8_t *p = LocalAddress; 210234353Sdim uint64_t ValueToWrite = Value + Addend; 211234353Sdim for (unsigned i = 0; i < Size; ++i) { 212234353Sdim *p++ = (uint8_t)(ValueToWrite & 0xff); 213234353Sdim ValueToWrite >>= 8; 214234353Sdim } 215249423Sdim return false; 216234353Sdim } 217261991Sdim case MachO::GENERIC_RELOC_SECTDIFF: 218261991Sdim case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: 219261991Sdim case MachO::GENERIC_RELOC_PB_LA_PTR: 220234353Sdim return Error("Relocation type not implemented yet!"); 221234353Sdim } 222234353Sdim} 223234353Sdim 224239462Sdimbool RuntimeDyldMachO::resolveX86_64Relocation(uint8_t *LocalAddress, 225239462Sdim uint64_t FinalAddress, 226239462Sdim uint64_t Value, 227239462Sdim bool isPCRel, 228239462Sdim unsigned Type, 229239462Sdim unsigned Size, 230239462Sdim int64_t Addend) { 231224133Sdim // If the relocation is PC-relative, the value to be encoded is the 232224133Sdim // pointer difference. 233224133Sdim if (isPCRel) 234224133Sdim // FIXME: It seems this value needs to be adjusted by 4 for an effective PC 235224133Sdim // address. Is that expected? Only for branches, perhaps? 236234353Sdim Value -= FinalAddress + 4; 237224133Sdim 238224133Sdim switch(Type) { 239224133Sdim default: 240224133Sdim llvm_unreachable("Invalid relocation type!"); 241261991Sdim case MachO::X86_64_RELOC_SIGNED_1: 242261991Sdim case MachO::X86_64_RELOC_SIGNED_2: 243261991Sdim case MachO::X86_64_RELOC_SIGNED_4: 244261991Sdim case MachO::X86_64_RELOC_SIGNED: 245261991Sdim case MachO::X86_64_RELOC_UNSIGNED: 246261991Sdim case MachO::X86_64_RELOC_BRANCH: { 247234353Sdim Value += Addend; 248224133Sdim // Mask in the target value a byte at a time (we don't have an alignment 249224133Sdim // guarantee for the target address, so this is safest). 250234353Sdim uint8_t *p = (uint8_t*)LocalAddress; 251224133Sdim for (unsigned i = 0; i < Size; ++i) { 252224133Sdim *p++ = (uint8_t)Value; 253224133Sdim Value >>= 8; 254224133Sdim } 255224133Sdim return false; 256224133Sdim } 257261991Sdim case MachO::X86_64_RELOC_GOT_LOAD: 258261991Sdim case MachO::X86_64_RELOC_GOT: 259261991Sdim case MachO::X86_64_RELOC_SUBTRACTOR: 260261991Sdim case MachO::X86_64_RELOC_TLV: 261224133Sdim return Error("Relocation type not implemented yet!"); 262224133Sdim } 263224133Sdim} 264224133Sdim 265239462Sdimbool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress, 266239462Sdim uint64_t FinalAddress, 267239462Sdim uint64_t Value, 268239462Sdim bool isPCRel, 269239462Sdim unsigned Type, 270239462Sdim unsigned Size, 271239462Sdim int64_t Addend) { 272224133Sdim // If the relocation is PC-relative, the value to be encoded is the 273224133Sdim // pointer difference. 274224133Sdim if (isPCRel) { 275234353Sdim Value -= FinalAddress; 276224133Sdim // ARM PCRel relocations have an effective-PC offset of two instructions 277224133Sdim // (four bytes in Thumb mode, 8 bytes in ARM mode). 278224133Sdim // FIXME: For now, assume ARM mode. 279224133Sdim Value -= 8; 280224133Sdim } 281224133Sdim 282224133Sdim switch(Type) { 283224133Sdim default: 284224133Sdim llvm_unreachable("Invalid relocation type!"); 285261991Sdim case MachO::ARM_RELOC_VANILLA: { 286224133Sdim // Mask in the target value a byte at a time (we don't have an alignment 287224133Sdim // guarantee for the target address, so this is safest). 288234353Sdim uint8_t *p = (uint8_t*)LocalAddress; 289224133Sdim for (unsigned i = 0; i < Size; ++i) { 290224133Sdim *p++ = (uint8_t)Value; 291224133Sdim Value >>= 8; 292224133Sdim } 293224133Sdim break; 294224133Sdim } 295261991Sdim case MachO::ARM_RELOC_BR24: { 296224133Sdim // Mask the value into the target address. We know instructions are 297224133Sdim // 32-bit aligned, so we can do it all at once. 298234353Sdim uint32_t *p = (uint32_t*)LocalAddress; 299224133Sdim // The low two bits of the value are not encoded. 300224133Sdim Value >>= 2; 301224133Sdim // Mask the value to 24 bits. 302224133Sdim Value &= 0xffffff; 303224133Sdim // FIXME: If the destination is a Thumb function (and the instruction 304224133Sdim // is a non-predicated BL instruction), we need to change it to a BLX 305224133Sdim // instruction instead. 306224133Sdim 307224133Sdim // Insert the value into the instruction. 308224133Sdim *p = (*p & ~0xffffff) | Value; 309224133Sdim break; 310224133Sdim } 311261991Sdim case MachO::ARM_THUMB_RELOC_BR22: 312261991Sdim case MachO::ARM_THUMB_32BIT_BRANCH: 313261991Sdim case MachO::ARM_RELOC_HALF: 314261991Sdim case MachO::ARM_RELOC_HALF_SECTDIFF: 315261991Sdim case MachO::ARM_RELOC_PAIR: 316261991Sdim case MachO::ARM_RELOC_SECTDIFF: 317261991Sdim case MachO::ARM_RELOC_LOCAL_SECTDIFF: 318261991Sdim case MachO::ARM_RELOC_PB_LA_PTR: 319224133Sdim return Error("Relocation type not implemented yet!"); 320224133Sdim } 321224133Sdim return false; 322224133Sdim} 323224133Sdim 324251662Sdimvoid RuntimeDyldMachO::processRelocationRef(unsigned SectionID, 325251662Sdim RelocationRef RelI, 326234982Sdim ObjectImage &Obj, 327234353Sdim ObjSectionToIDMap &ObjSectionToID, 328239462Sdim const SymbolTableMap &Symbols, 329234353Sdim StubMap &Stubs) { 330251662Sdim const ObjectFile *OF = Obj.getObjectFile(); 331251662Sdim const MachOObjectFile *MachO = static_cast<const MachOObjectFile*>(OF); 332261991Sdim MachO::any_relocation_info RE= MachO->getRelocation(RelI.getRawDataRefImpl()); 333224133Sdim 334251662Sdim uint32_t RelType = MachO->getAnyRelocationType(RE); 335261991Sdim 336261991Sdim // FIXME: Properly handle scattered relocations. 337261991Sdim // For now, optimistically skip these: they can often be ignored, as 338261991Sdim // the static linker will already have applied the relocation, and it 339261991Sdim // only needs to be reapplied if symbols move relative to one another. 340261991Sdim // Note: This will fail horribly where the relocations *do* need to be 341261991Sdim // applied, but that was already the case. 342261991Sdim if (MachO->isRelocationScattered(RE)) 343261991Sdim return; 344261991Sdim 345234353Sdim RelocationValueRef Value; 346251662Sdim SectionEntry &Section = Sections[SectionID]; 347224133Sdim 348251662Sdim bool isExtern = MachO->getPlainRelocationExternal(RE); 349251662Sdim bool IsPCRel = MachO->getAnyRelocationPCRel(RE); 350251662Sdim unsigned Size = MachO->getAnyRelocationLength(RE); 351251662Sdim uint64_t Offset; 352251662Sdim RelI.getOffset(Offset); 353251662Sdim uint8_t *LocalAddress = Section.Address + Offset; 354251662Sdim unsigned NumBytes = 1 << Size; 355251662Sdim uint64_t Addend = 0; 356251662Sdim memcpy(&Addend, LocalAddress, NumBytes); 357251662Sdim 358234353Sdim if (isExtern) { 359239462Sdim // Obtain the symbol name which is referenced in the relocation 360261991Sdim symbol_iterator Symbol = RelI.getSymbol(); 361234353Sdim StringRef TargetName; 362261991Sdim Symbol->getName(TargetName); 363239462Sdim // First search for the symbol in the local symbol table 364239462Sdim SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data()); 365234353Sdim if (lsi != Symbols.end()) { 366234353Sdim Value.SectionID = lsi->second.first; 367251662Sdim Value.Addend = lsi->second.second + Addend; 368234353Sdim } else { 369239462Sdim // Search for the symbol in the global symbol table 370239462Sdim SymbolTableMap::const_iterator gsi = GlobalSymbolTable.find(TargetName.data()); 371239462Sdim if (gsi != GlobalSymbolTable.end()) { 372234353Sdim Value.SectionID = gsi->second.first; 373251662Sdim Value.Addend = gsi->second.second + Addend; 374251662Sdim } else { 375234353Sdim Value.SymbolName = TargetName.data(); 376251662Sdim Value.Addend = Addend; 377251662Sdim } 378224133Sdim } 379234353Sdim } else { 380251662Sdim SectionRef Sec = MachO->getRelocationSection(RE); 381251662Sdim Value.SectionID = findOrEmitSection(Obj, Sec, true, ObjSectionToID); 382251662Sdim uint64_t Addr; 383251662Sdim Sec.getAddress(Addr); 384251662Sdim Value.Addend = Addend - Addr; 385224133Sdim } 386224133Sdim 387261991Sdim if (Arch == Triple::x86_64 && (RelType == MachO::X86_64_RELOC_GOT || 388261991Sdim RelType == MachO::X86_64_RELOC_GOT_LOAD)) { 389251662Sdim assert(IsPCRel); 390251662Sdim assert(Size == 2); 391251662Sdim StubMap::const_iterator i = Stubs.find(Value); 392251662Sdim uint8_t *Addr; 393251662Sdim if (i != Stubs.end()) { 394251662Sdim Addr = Section.Address + i->second; 395251662Sdim } else { 396251662Sdim Stubs[Value] = Section.StubOffset; 397251662Sdim uint8_t *GOTEntry = Section.Address + Section.StubOffset; 398251662Sdim RelocationEntry RE(SectionID, Section.StubOffset, 399261991Sdim MachO::X86_64_RELOC_UNSIGNED, 0, false, 3); 400251662Sdim if (Value.SymbolName) 401251662Sdim addRelocationForSymbol(RE, Value.SymbolName); 402251662Sdim else 403251662Sdim addRelocationForSection(RE, Value.SectionID); 404251662Sdim Section.StubOffset += 8; 405251662Sdim Addr = GOTEntry; 406251662Sdim } 407251662Sdim resolveRelocation(Section, Offset, (uint64_t)Addr, 408261991Sdim MachO::X86_64_RELOC_UNSIGNED, Value.Addend, true, 2); 409251662Sdim } else if (Arch == Triple::arm && 410261991Sdim (RelType & 0xf) == MachO::ARM_RELOC_BR24) { 411234353Sdim // This is an ARM branch relocation, need to use a stub function. 412224133Sdim 413234353Sdim // Look up for existing stub. 414234353Sdim StubMap::const_iterator i = Stubs.find(Value); 415234353Sdim if (i != Stubs.end()) 416251662Sdim resolveRelocation(Section, Offset, 417234353Sdim (uint64_t)Section.Address + i->second, 418251662Sdim RelType, 0, IsPCRel, Size); 419234353Sdim else { 420234353Sdim // Create a new stub function. 421234353Sdim Stubs[Value] = Section.StubOffset; 422234353Sdim uint8_t *StubTargetAddr = createStubFunction(Section.Address + 423234353Sdim Section.StubOffset); 424251662Sdim RelocationEntry RE(SectionID, StubTargetAddr - Section.Address, 425261991Sdim MachO::GENERIC_RELOC_VANILLA, Value.Addend); 426239462Sdim if (Value.SymbolName) 427239462Sdim addRelocationForSymbol(RE, Value.SymbolName); 428239462Sdim else 429239462Sdim addRelocationForSection(RE, Value.SectionID); 430251662Sdim resolveRelocation(Section, Offset, 431234353Sdim (uint64_t)Section.Address + Section.StubOffset, 432251662Sdim RelType, 0, IsPCRel, Size); 433234353Sdim Section.StubOffset += getMaxStubSize(); 434224133Sdim } 435239462Sdim } else { 436251662Sdim RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, 437251662Sdim IsPCRel, Size); 438239462Sdim if (Value.SymbolName) 439239462Sdim addRelocationForSymbol(RE, Value.SymbolName); 440239462Sdim else 441239462Sdim addRelocationForSection(RE, Value.SectionID); 442239462Sdim } 443224133Sdim} 444224133Sdim 445224133Sdim 446239462Sdimbool RuntimeDyldMachO::isCompatibleFormat( 447243830Sdim const ObjectBuffer *InputBuffer) const { 448243830Sdim if (InputBuffer->getBufferSize() < 4) 449243830Sdim return false; 450243830Sdim StringRef Magic(InputBuffer->getBufferStart(), 4); 451224133Sdim if (Magic == "\xFE\xED\xFA\xCE") return true; 452224133Sdim if (Magic == "\xCE\xFA\xED\xFE") return true; 453224133Sdim if (Magic == "\xFE\xED\xFA\xCF") return true; 454224133Sdim if (Magic == "\xCF\xFA\xED\xFE") return true; 455224133Sdim return false; 456224133Sdim} 457224133Sdim 458224133Sdim} // end namespace llvm 459