RuntimeDyldMachO.cpp revision 243830
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" 15224133Sdim#include "llvm/ADT/OwningPtr.h" 16224133Sdim#include "llvm/ADT/StringRef.h" 17224133Sdim#include "llvm/ADT/STLExtras.h" 18234353Sdim#include "RuntimeDyldMachO.h" 19224133Sdimusing namespace llvm; 20224133Sdimusing namespace llvm::object; 21224133Sdim 22224133Sdimnamespace llvm { 23224133Sdim 24243830Sdimvoid RuntimeDyldMachO::resolveRelocation(const SectionEntry &Section, 25243830Sdim uint64_t Offset, 26234353Sdim uint64_t Value, 27234353Sdim uint32_t Type, 28234353Sdim int64_t Addend) { 29243830Sdim uint8_t *LocalAddress = Section.Address + Offset; 30243830Sdim uint64_t FinalAddress = Section.LoadAddress + Offset; 31234353Sdim bool isPCRel = (Type >> 24) & 1; 32234353Sdim unsigned MachoType = (Type >> 28) & 0xf; 33234353Sdim unsigned Size = 1 << ((Type >> 25) & 3); 34234353Sdim 35239462Sdim DEBUG(dbgs() << "resolveRelocation LocalAddress: " 36239462Sdim << format("%p", LocalAddress) 37234353Sdim << " FinalAddress: " << format("%p", FinalAddress) 38234353Sdim << " Value: " << format("%p", Value) 39234353Sdim << " Addend: " << Addend 40234353Sdim << " isPCRel: " << isPCRel 41234353Sdim << " MachoType: " << MachoType 42234353Sdim << " Size: " << Size 43234353Sdim << "\n"); 44234353Sdim 45224133Sdim // This just dispatches to the proper target specific routine. 46234353Sdim switch (Arch) { 47234353Sdim default: llvm_unreachable("Unsupported CPU type!"); 48234353Sdim case Triple::x86_64: 49234353Sdim resolveX86_64Relocation(LocalAddress, 50234353Sdim FinalAddress, 51234353Sdim (uintptr_t)Value, 52234353Sdim isPCRel, 53234353Sdim MachoType, 54234353Sdim Size, 55234353Sdim Addend); 56234353Sdim break; 57234353Sdim case Triple::x86: 58234353Sdim resolveI386Relocation(LocalAddress, 59239462Sdim FinalAddress, 60239462Sdim (uintptr_t)Value, 61239462Sdim isPCRel, 62243830Sdim MachoType, 63239462Sdim Size, 64239462Sdim Addend); 65234353Sdim break; 66234353Sdim case Triple::arm: // Fall through. 67234353Sdim case Triple::thumb: 68234353Sdim resolveARMRelocation(LocalAddress, 69234353Sdim FinalAddress, 70234353Sdim (uintptr_t)Value, 71234353Sdim isPCRel, 72234353Sdim MachoType, 73234353Sdim Size, 74234353Sdim Addend); 75234353Sdim break; 76224133Sdim } 77224133Sdim} 78224133Sdim 79239462Sdimbool RuntimeDyldMachO::resolveI386Relocation(uint8_t *LocalAddress, 80239462Sdim uint64_t FinalAddress, 81239462Sdim uint64_t Value, 82239462Sdim bool isPCRel, 83239462Sdim unsigned Type, 84239462Sdim unsigned Size, 85239462Sdim int64_t Addend) { 86234353Sdim if (isPCRel) 87234353Sdim Value -= FinalAddress + 4; // see resolveX86_64Relocation 88234353Sdim 89234353Sdim switch (Type) { 90234353Sdim default: 91234353Sdim llvm_unreachable("Invalid relocation type!"); 92234353Sdim case macho::RIT_Vanilla: { 93234353Sdim uint8_t *p = LocalAddress; 94234353Sdim uint64_t ValueToWrite = Value + Addend; 95234353Sdim for (unsigned i = 0; i < Size; ++i) { 96234353Sdim *p++ = (uint8_t)(ValueToWrite & 0xff); 97234353Sdim ValueToWrite >>= 8; 98234353Sdim } 99234353Sdim } 100234353Sdim case macho::RIT_Difference: 101234353Sdim case macho::RIT_Generic_LocalDifference: 102234353Sdim case macho::RIT_Generic_PreboundLazyPointer: 103234353Sdim return Error("Relocation type not implemented yet!"); 104234353Sdim } 105234353Sdim} 106234353Sdim 107239462Sdimbool RuntimeDyldMachO::resolveX86_64Relocation(uint8_t *LocalAddress, 108239462Sdim uint64_t FinalAddress, 109239462Sdim uint64_t Value, 110239462Sdim bool isPCRel, 111239462Sdim unsigned Type, 112239462Sdim unsigned Size, 113239462Sdim int64_t Addend) { 114224133Sdim // If the relocation is PC-relative, the value to be encoded is the 115224133Sdim // pointer difference. 116224133Sdim if (isPCRel) 117224133Sdim // FIXME: It seems this value needs to be adjusted by 4 for an effective PC 118224133Sdim // address. Is that expected? Only for branches, perhaps? 119234353Sdim Value -= FinalAddress + 4; 120224133Sdim 121224133Sdim switch(Type) { 122224133Sdim default: 123224133Sdim llvm_unreachable("Invalid relocation type!"); 124234353Sdim case macho::RIT_X86_64_Signed1: 125234353Sdim case macho::RIT_X86_64_Signed2: 126234353Sdim case macho::RIT_X86_64_Signed4: 127234353Sdim case macho::RIT_X86_64_Signed: 128224133Sdim case macho::RIT_X86_64_Unsigned: 129224133Sdim case macho::RIT_X86_64_Branch: { 130234353Sdim Value += Addend; 131224133Sdim // Mask in the target value a byte at a time (we don't have an alignment 132224133Sdim // guarantee for the target address, so this is safest). 133234353Sdim uint8_t *p = (uint8_t*)LocalAddress; 134224133Sdim for (unsigned i = 0; i < Size; ++i) { 135224133Sdim *p++ = (uint8_t)Value; 136224133Sdim Value >>= 8; 137224133Sdim } 138224133Sdim return false; 139224133Sdim } 140224133Sdim case macho::RIT_X86_64_GOTLoad: 141224133Sdim case macho::RIT_X86_64_GOT: 142224133Sdim case macho::RIT_X86_64_Subtractor: 143224133Sdim case macho::RIT_X86_64_TLV: 144224133Sdim return Error("Relocation type not implemented yet!"); 145224133Sdim } 146224133Sdim} 147224133Sdim 148239462Sdimbool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress, 149239462Sdim uint64_t FinalAddress, 150239462Sdim uint64_t Value, 151239462Sdim bool isPCRel, 152239462Sdim unsigned Type, 153239462Sdim unsigned Size, 154239462Sdim int64_t Addend) { 155224133Sdim // If the relocation is PC-relative, the value to be encoded is the 156224133Sdim // pointer difference. 157224133Sdim if (isPCRel) { 158234353Sdim Value -= FinalAddress; 159224133Sdim // ARM PCRel relocations have an effective-PC offset of two instructions 160224133Sdim // (four bytes in Thumb mode, 8 bytes in ARM mode). 161224133Sdim // FIXME: For now, assume ARM mode. 162224133Sdim Value -= 8; 163224133Sdim } 164224133Sdim 165224133Sdim switch(Type) { 166224133Sdim default: 167224133Sdim llvm_unreachable("Invalid relocation type!"); 168224133Sdim case macho::RIT_Vanilla: { 169224133Sdim // Mask in the target value a byte at a time (we don't have an alignment 170224133Sdim // guarantee for the target address, so this is safest). 171234353Sdim uint8_t *p = (uint8_t*)LocalAddress; 172224133Sdim for (unsigned i = 0; i < Size; ++i) { 173224133Sdim *p++ = (uint8_t)Value; 174224133Sdim Value >>= 8; 175224133Sdim } 176224133Sdim break; 177224133Sdim } 178224133Sdim case macho::RIT_ARM_Branch24Bit: { 179224133Sdim // Mask the value into the target address. We know instructions are 180224133Sdim // 32-bit aligned, so we can do it all at once. 181234353Sdim uint32_t *p = (uint32_t*)LocalAddress; 182224133Sdim // The low two bits of the value are not encoded. 183224133Sdim Value >>= 2; 184224133Sdim // Mask the value to 24 bits. 185224133Sdim Value &= 0xffffff; 186224133Sdim // FIXME: If the destination is a Thumb function (and the instruction 187224133Sdim // is a non-predicated BL instruction), we need to change it to a BLX 188224133Sdim // instruction instead. 189224133Sdim 190224133Sdim // Insert the value into the instruction. 191224133Sdim *p = (*p & ~0xffffff) | Value; 192224133Sdim break; 193224133Sdim } 194224133Sdim case macho::RIT_ARM_ThumbBranch22Bit: 195224133Sdim case macho::RIT_ARM_ThumbBranch32Bit: 196224133Sdim case macho::RIT_ARM_Half: 197224133Sdim case macho::RIT_ARM_HalfDifference: 198224133Sdim case macho::RIT_Pair: 199224133Sdim case macho::RIT_Difference: 200224133Sdim case macho::RIT_ARM_LocalDifference: 201224133Sdim case macho::RIT_ARM_PreboundLazyPointer: 202224133Sdim return Error("Relocation type not implemented yet!"); 203224133Sdim } 204224133Sdim return false; 205224133Sdim} 206224133Sdim 207234353Sdimvoid RuntimeDyldMachO::processRelocationRef(const ObjRelocationInfo &Rel, 208234982Sdim ObjectImage &Obj, 209234353Sdim ObjSectionToIDMap &ObjSectionToID, 210239462Sdim const SymbolTableMap &Symbols, 211234353Sdim StubMap &Stubs) { 212224133Sdim 213234353Sdim uint32_t RelType = (uint32_t) (Rel.Type & 0xffffffffL); 214234353Sdim RelocationValueRef Value; 215234353Sdim SectionEntry &Section = Sections[Rel.SectionID]; 216224133Sdim 217234353Sdim bool isExtern = (RelType >> 27) & 1; 218234353Sdim if (isExtern) { 219239462Sdim // Obtain the symbol name which is referenced in the relocation 220234353Sdim StringRef TargetName; 221234353Sdim const SymbolRef &Symbol = Rel.Symbol; 222234353Sdim Symbol.getName(TargetName); 223239462Sdim // First search for the symbol in the local symbol table 224239462Sdim SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data()); 225234353Sdim if (lsi != Symbols.end()) { 226234353Sdim Value.SectionID = lsi->second.first; 227234353Sdim Value.Addend = lsi->second.second; 228234353Sdim } else { 229239462Sdim // Search for the symbol in the global symbol table 230239462Sdim SymbolTableMap::const_iterator gsi = GlobalSymbolTable.find(TargetName.data()); 231239462Sdim if (gsi != GlobalSymbolTable.end()) { 232234353Sdim Value.SectionID = gsi->second.first; 233234353Sdim Value.Addend = gsi->second.second; 234234353Sdim } else 235234353Sdim Value.SymbolName = TargetName.data(); 236224133Sdim } 237234353Sdim } else { 238234353Sdim error_code err; 239234353Sdim uint8_t sectionIndex = static_cast<uint8_t>(RelType & 0xFF); 240234353Sdim section_iterator si = Obj.begin_sections(), 241234353Sdim se = Obj.end_sections(); 242234353Sdim for (uint8_t i = 1; i < sectionIndex; i++) { 243234353Sdim error_code err; 244234353Sdim si.increment(err); 245234353Sdim if (si == se) 246234353Sdim break; 247224133Sdim } 248234353Sdim assert(si != se && "No section containing relocation!"); 249234982Sdim Value.SectionID = findOrEmitSection(Obj, *si, true, ObjSectionToID); 250243830Sdim Value.Addend = 0; 251243830Sdim // FIXME: The size and type of the relocation determines if we can 252243830Sdim // encode an Addend in the target location itself, and if so, how many 253243830Sdim // bytes we should read in order to get it. We don't yet support doing 254243830Sdim // that, and just assuming it's sizeof(intptr_t) is blatantly wrong. 255243830Sdim //Value.Addend = *(const intptr_t *)Target; 256234353Sdim if (Value.Addend) { 257239462Sdim // The MachO addend is an offset from the current section. We need it 258239462Sdim // to be an offset from the destination section 259234353Sdim Value.Addend += Section.ObjAddress - Sections[Value.SectionID].ObjAddress; 260224133Sdim } 261224133Sdim } 262224133Sdim 263243830Sdim if (Arch == Triple::arm && (RelType & 0xf) == macho::RIT_ARM_Branch24Bit) { 264234353Sdim // This is an ARM branch relocation, need to use a stub function. 265224133Sdim 266234353Sdim // Look up for existing stub. 267234353Sdim StubMap::const_iterator i = Stubs.find(Value); 268234353Sdim if (i != Stubs.end()) 269243830Sdim resolveRelocation(Section, Rel.Offset, 270234353Sdim (uint64_t)Section.Address + i->second, 271234353Sdim RelType, 0); 272234353Sdim else { 273234353Sdim // Create a new stub function. 274234353Sdim Stubs[Value] = Section.StubOffset; 275234353Sdim uint8_t *StubTargetAddr = createStubFunction(Section.Address + 276234353Sdim Section.StubOffset); 277239462Sdim RelocationEntry RE(Rel.SectionID, StubTargetAddr - Section.Address, 278239462Sdim macho::RIT_Vanilla, Value.Addend); 279239462Sdim if (Value.SymbolName) 280239462Sdim addRelocationForSymbol(RE, Value.SymbolName); 281239462Sdim else 282239462Sdim addRelocationForSection(RE, Value.SectionID); 283243830Sdim resolveRelocation(Section, Rel.Offset, 284234353Sdim (uint64_t)Section.Address + Section.StubOffset, 285234353Sdim RelType, 0); 286234353Sdim Section.StubOffset += getMaxStubSize(); 287224133Sdim } 288239462Sdim } else { 289239462Sdim RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType, Value.Addend); 290239462Sdim if (Value.SymbolName) 291239462Sdim addRelocationForSymbol(RE, Value.SymbolName); 292239462Sdim else 293239462Sdim addRelocationForSection(RE, Value.SectionID); 294239462Sdim } 295224133Sdim} 296224133Sdim 297224133Sdim 298239462Sdimbool RuntimeDyldMachO::isCompatibleFormat( 299243830Sdim const ObjectBuffer *InputBuffer) const { 300243830Sdim if (InputBuffer->getBufferSize() < 4) 301243830Sdim return false; 302243830Sdim StringRef Magic(InputBuffer->getBufferStart(), 4); 303224133Sdim if (Magic == "\xFE\xED\xFA\xCE") return true; 304224133Sdim if (Magic == "\xCE\xFA\xED\xFE") return true; 305224133Sdim if (Magic == "\xFE\xED\xFA\xCF") return true; 306224133Sdim if (Magic == "\xCF\xFA\xED\xFE") return true; 307224133Sdim return false; 308224133Sdim} 309224133Sdim 310224133Sdim} // end namespace llvm 311