RuntimeDyldMachO.cpp revision 234982
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 24234353Sdimvoid RuntimeDyldMachO::resolveRelocation(uint8_t *LocalAddress, 25234353Sdim uint64_t FinalAddress, 26234353Sdim uint64_t Value, 27234353Sdim uint32_t Type, 28234353Sdim int64_t Addend) { 29234353Sdim bool isPCRel = (Type >> 24) & 1; 30234353Sdim unsigned MachoType = (Type >> 28) & 0xf; 31234353Sdim unsigned Size = 1 << ((Type >> 25) & 3); 32234353Sdim 33234353Sdim DEBUG(dbgs() << "resolveRelocation LocalAddress: " << format("%p", LocalAddress) 34234353Sdim << " FinalAddress: " << format("%p", FinalAddress) 35234353Sdim << " Value: " << format("%p", Value) 36234353Sdim << " Addend: " << Addend 37234353Sdim << " isPCRel: " << isPCRel 38234353Sdim << " MachoType: " << MachoType 39234353Sdim << " Size: " << Size 40234353Sdim << "\n"); 41234353Sdim 42224133Sdim // This just dispatches to the proper target specific routine. 43234353Sdim switch (Arch) { 44234353Sdim default: llvm_unreachable("Unsupported CPU type!"); 45234353Sdim case Triple::x86_64: 46234353Sdim resolveX86_64Relocation(LocalAddress, 47234353Sdim FinalAddress, 48234353Sdim (uintptr_t)Value, 49234353Sdim isPCRel, 50234353Sdim MachoType, 51234353Sdim Size, 52234353Sdim Addend); 53234353Sdim break; 54234353Sdim case Triple::x86: 55234353Sdim resolveI386Relocation(LocalAddress, 56234353Sdim FinalAddress, 57234353Sdim (uintptr_t)Value, 58234353Sdim isPCRel, 59234353Sdim Type, 60234353Sdim Size, 61234353Sdim Addend); 62234353Sdim break; 63234353Sdim case Triple::arm: // Fall through. 64234353Sdim case Triple::thumb: 65234353Sdim resolveARMRelocation(LocalAddress, 66234353Sdim FinalAddress, 67234353Sdim (uintptr_t)Value, 68234353Sdim isPCRel, 69234353Sdim MachoType, 70234353Sdim Size, 71234353Sdim Addend); 72234353Sdim break; 73224133Sdim } 74224133Sdim} 75224133Sdim 76224133Sdimbool RuntimeDyldMachO:: 77234353SdimresolveI386Relocation(uint8_t *LocalAddress, 78234353Sdim uint64_t FinalAddress, 79234353Sdim uint64_t Value, 80234353Sdim bool isPCRel, 81234353Sdim unsigned Type, 82234353Sdim unsigned Size, 83234353Sdim int64_t Addend) { 84234353Sdim if (isPCRel) 85234353Sdim Value -= FinalAddress + 4; // see resolveX86_64Relocation 86234353Sdim 87234353Sdim switch (Type) { 88234353Sdim default: 89234353Sdim llvm_unreachable("Invalid relocation type!"); 90234353Sdim case macho::RIT_Vanilla: { 91234353Sdim uint8_t *p = LocalAddress; 92234353Sdim uint64_t ValueToWrite = Value + Addend; 93234353Sdim for (unsigned i = 0; i < Size; ++i) { 94234353Sdim *p++ = (uint8_t)(ValueToWrite & 0xff); 95234353Sdim ValueToWrite >>= 8; 96234353Sdim } 97234353Sdim } 98234353Sdim case macho::RIT_Difference: 99234353Sdim case macho::RIT_Generic_LocalDifference: 100234353Sdim case macho::RIT_Generic_PreboundLazyPointer: 101234353Sdim return Error("Relocation type not implemented yet!"); 102234353Sdim } 103234353Sdim} 104234353Sdim 105234353Sdimbool RuntimeDyldMachO:: 106234353SdimresolveX86_64Relocation(uint8_t *LocalAddress, 107234353Sdim uint64_t FinalAddress, 108234353Sdim uint64_t Value, 109234353Sdim bool isPCRel, 110234353Sdim unsigned Type, 111234353Sdim unsigned Size, 112234353Sdim int64_t Addend) { 113224133Sdim // If the relocation is PC-relative, the value to be encoded is the 114224133Sdim // pointer difference. 115224133Sdim if (isPCRel) 116224133Sdim // FIXME: It seems this value needs to be adjusted by 4 for an effective PC 117224133Sdim // address. Is that expected? Only for branches, perhaps? 118234353Sdim Value -= FinalAddress + 4; 119224133Sdim 120224133Sdim switch(Type) { 121224133Sdim default: 122224133Sdim llvm_unreachable("Invalid relocation type!"); 123234353Sdim case macho::RIT_X86_64_Signed1: 124234353Sdim case macho::RIT_X86_64_Signed2: 125234353Sdim case macho::RIT_X86_64_Signed4: 126234353Sdim case macho::RIT_X86_64_Signed: 127224133Sdim case macho::RIT_X86_64_Unsigned: 128224133Sdim case macho::RIT_X86_64_Branch: { 129234353Sdim Value += Addend; 130224133Sdim // Mask in the target value a byte at a time (we don't have an alignment 131224133Sdim // guarantee for the target address, so this is safest). 132234353Sdim uint8_t *p = (uint8_t*)LocalAddress; 133224133Sdim for (unsigned i = 0; i < Size; ++i) { 134224133Sdim *p++ = (uint8_t)Value; 135224133Sdim Value >>= 8; 136224133Sdim } 137224133Sdim return false; 138224133Sdim } 139224133Sdim case macho::RIT_X86_64_GOTLoad: 140224133Sdim case macho::RIT_X86_64_GOT: 141224133Sdim case macho::RIT_X86_64_Subtractor: 142224133Sdim case macho::RIT_X86_64_TLV: 143224133Sdim return Error("Relocation type not implemented yet!"); 144224133Sdim } 145224133Sdim} 146224133Sdim 147234353Sdimbool RuntimeDyldMachO:: 148234353SdimresolveARMRelocation(uint8_t *LocalAddress, 149234353Sdim uint64_t FinalAddress, 150234353Sdim uint64_t Value, 151234353Sdim bool isPCRel, 152234353Sdim unsigned Type, 153234353Sdim unsigned Size, 154234353Sdim 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, 210234353Sdim LocalSymbolMap &Symbols, 211234353Sdim StubMap &Stubs) { 212224133Sdim 213234353Sdim uint32_t RelType = (uint32_t) (Rel.Type & 0xffffffffL); 214234353Sdim RelocationValueRef Value; 215234353Sdim SectionEntry &Section = Sections[Rel.SectionID]; 216234353Sdim uint8_t *Target = Section.Address + Rel.Offset; 217224133Sdim 218234353Sdim bool isExtern = (RelType >> 27) & 1; 219234353Sdim if (isExtern) { 220234353Sdim StringRef TargetName; 221234353Sdim const SymbolRef &Symbol = Rel.Symbol; 222234353Sdim Symbol.getName(TargetName); 223234353Sdim // First look the symbol in object file symbols. 224234353Sdim LocalSymbolMap::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 { 229234353Sdim // Second look the symbol in global symbol table. 230234353Sdim StringMap<SymbolLoc>::iterator gsi = SymbolTable.find(TargetName.data()); 231234353Sdim if (gsi != SymbolTable.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); 250234353Sdim Value.Addend = *(const intptr_t *)Target; 251234353Sdim if (Value.Addend) { 252234353Sdim // The MachO addend is offset from the current section, we need set it 253234353Sdim // as offset from destination section 254234353Sdim Value.Addend += Section.ObjAddress - Sections[Value.SectionID].ObjAddress; 255224133Sdim } 256224133Sdim } 257224133Sdim 258234353Sdim if (Arch == Triple::arm && RelType == macho::RIT_ARM_Branch24Bit) { 259234353Sdim // This is an ARM branch relocation, need to use a stub function. 260224133Sdim 261234353Sdim // Look up for existing stub. 262234353Sdim StubMap::const_iterator i = Stubs.find(Value); 263234353Sdim if (i != Stubs.end()) 264234353Sdim resolveRelocation(Target, (uint64_t)Target, 265234353Sdim (uint64_t)Section.Address + i->second, 266234353Sdim RelType, 0); 267234353Sdim else { 268234353Sdim // Create a new stub function. 269234353Sdim Stubs[Value] = Section.StubOffset; 270234353Sdim uint8_t *StubTargetAddr = createStubFunction(Section.Address + 271234353Sdim Section.StubOffset); 272234353Sdim AddRelocation(Value, Rel.SectionID, StubTargetAddr - Section.Address, 273234353Sdim macho::RIT_Vanilla); 274234353Sdim resolveRelocation(Target, (uint64_t)Target, 275234353Sdim (uint64_t)Section.Address + Section.StubOffset, 276234353Sdim RelType, 0); 277234353Sdim Section.StubOffset += getMaxStubSize(); 278224133Sdim } 279234353Sdim } else 280234353Sdim AddRelocation(Value, Rel.SectionID, Rel.Offset, RelType); 281224133Sdim} 282224133Sdim 283224133Sdim 284234353Sdimbool RuntimeDyldMachO::isCompatibleFormat(const MemoryBuffer *InputBuffer) const { 285224133Sdim StringRef Magic = InputBuffer->getBuffer().slice(0, 4); 286224133Sdim if (Magic == "\xFE\xED\xFA\xCE") return true; 287224133Sdim if (Magic == "\xCE\xFA\xED\xFE") return true; 288224133Sdim if (Magic == "\xFE\xED\xFA\xCF") return true; 289224133Sdim if (Magic == "\xCF\xFA\xED\xFE") return true; 290224133Sdim return false; 291224133Sdim} 292224133Sdim 293224133Sdim} // end namespace llvm 294