RuntimeDyldMachO.cpp revision ca0e73610056110e9a175c14dd82d6d616fd830f
1//===-- RuntimeDyldMachO.cpp - Run-time dynamic linker for MC-JIT -*- C++ -*-=// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// Implementation of the MC-JIT runtime dynamic linker. 11// 12//===----------------------------------------------------------------------===// 13 14#define DEBUG_TYPE "dyld" 15#include "RuntimeDyldMachO.h" 16#include "llvm/ADT/OwningPtr.h" 17#include "llvm/ADT/STLExtras.h" 18#include "llvm/ADT/StringRef.h" 19using namespace llvm; 20using namespace llvm::object; 21 22namespace llvm { 23 24void RuntimeDyldMachO::resolveRelocation(const RelocationEntry &RE, 25 uint64_t Value) { 26 const SectionEntry &Section = Sections[RE.SectionID]; 27 return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend, 28 RE.IsPCRel, RE.Size); 29} 30 31void RuntimeDyldMachO::resolveRelocation(const SectionEntry &Section, 32 uint64_t Offset, 33 uint64_t Value, 34 uint32_t Type, 35 int64_t Addend, 36 bool isPCRel, 37 unsigned LogSize) { 38 uint8_t *LocalAddress = Section.Address + Offset; 39 uint64_t FinalAddress = Section.LoadAddress + Offset; 40 unsigned MachoType = Type; 41 unsigned Size = 1 << LogSize; 42 43 DEBUG(dbgs() << "resolveRelocation LocalAddress: " 44 << format("%p", LocalAddress) 45 << " FinalAddress: " << format("%p", FinalAddress) 46 << " Value: " << format("%p", Value) 47 << " Addend: " << Addend 48 << " isPCRel: " << isPCRel 49 << " MachoType: " << MachoType 50 << " Size: " << Size 51 << "\n"); 52 53 // This just dispatches to the proper target specific routine. 54 switch (Arch) { 55 default: llvm_unreachable("Unsupported CPU type!"); 56 case Triple::x86_64: 57 resolveX86_64Relocation(LocalAddress, 58 FinalAddress, 59 (uintptr_t)Value, 60 isPCRel, 61 MachoType, 62 Size, 63 Addend); 64 break; 65 case Triple::x86: 66 resolveI386Relocation(LocalAddress, 67 FinalAddress, 68 (uintptr_t)Value, 69 isPCRel, 70 MachoType, 71 Size, 72 Addend); 73 break; 74 case Triple::arm: // Fall through. 75 case Triple::thumb: 76 resolveARMRelocation(LocalAddress, 77 FinalAddress, 78 (uintptr_t)Value, 79 isPCRel, 80 MachoType, 81 Size, 82 Addend); 83 break; 84 } 85} 86 87bool RuntimeDyldMachO::resolveI386Relocation(uint8_t *LocalAddress, 88 uint64_t FinalAddress, 89 uint64_t Value, 90 bool isPCRel, 91 unsigned Type, 92 unsigned Size, 93 int64_t Addend) { 94 if (isPCRel) 95 Value -= FinalAddress + 4; // see resolveX86_64Relocation 96 97 switch (Type) { 98 default: 99 llvm_unreachable("Invalid relocation type!"); 100 case macho::RIT_Vanilla: { 101 uint8_t *p = LocalAddress; 102 uint64_t ValueToWrite = Value + Addend; 103 for (unsigned i = 0; i < Size; ++i) { 104 *p++ = (uint8_t)(ValueToWrite & 0xff); 105 ValueToWrite >>= 8; 106 } 107 return false; 108 } 109 case macho::RIT_Difference: 110 case macho::RIT_Generic_LocalDifference: 111 case macho::RIT_Generic_PreboundLazyPointer: 112 return Error("Relocation type not implemented yet!"); 113 } 114} 115 116bool RuntimeDyldMachO::resolveX86_64Relocation(uint8_t *LocalAddress, 117 uint64_t FinalAddress, 118 uint64_t Value, 119 bool isPCRel, 120 unsigned Type, 121 unsigned Size, 122 int64_t Addend) { 123 // If the relocation is PC-relative, the value to be encoded is the 124 // pointer difference. 125 if (isPCRel) 126 // FIXME: It seems this value needs to be adjusted by 4 for an effective PC 127 // address. Is that expected? Only for branches, perhaps? 128 Value -= FinalAddress + 4; 129 130 switch(Type) { 131 default: 132 llvm_unreachable("Invalid relocation type!"); 133 case macho::RIT_X86_64_Signed1: 134 case macho::RIT_X86_64_Signed2: 135 case macho::RIT_X86_64_Signed4: 136 case macho::RIT_X86_64_Signed: 137 case macho::RIT_X86_64_Unsigned: 138 case macho::RIT_X86_64_Branch: { 139 Value += Addend; 140 // Mask in the target value a byte at a time (we don't have an alignment 141 // guarantee for the target address, so this is safest). 142 uint8_t *p = (uint8_t*)LocalAddress; 143 for (unsigned i = 0; i < Size; ++i) { 144 *p++ = (uint8_t)Value; 145 Value >>= 8; 146 } 147 return false; 148 } 149 case macho::RIT_X86_64_GOTLoad: 150 case macho::RIT_X86_64_GOT: 151 case macho::RIT_X86_64_Subtractor: 152 case macho::RIT_X86_64_TLV: 153 return Error("Relocation type not implemented yet!"); 154 } 155} 156 157bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress, 158 uint64_t FinalAddress, 159 uint64_t Value, 160 bool isPCRel, 161 unsigned Type, 162 unsigned Size, 163 int64_t Addend) { 164 // If the relocation is PC-relative, the value to be encoded is the 165 // pointer difference. 166 if (isPCRel) { 167 Value -= FinalAddress; 168 // ARM PCRel relocations have an effective-PC offset of two instructions 169 // (four bytes in Thumb mode, 8 bytes in ARM mode). 170 // FIXME: For now, assume ARM mode. 171 Value -= 8; 172 } 173 174 switch(Type) { 175 default: 176 llvm_unreachable("Invalid relocation type!"); 177 case macho::RIT_Vanilla: { 178 // Mask in the target value a byte at a time (we don't have an alignment 179 // guarantee for the target address, so this is safest). 180 uint8_t *p = (uint8_t*)LocalAddress; 181 for (unsigned i = 0; i < Size; ++i) { 182 *p++ = (uint8_t)Value; 183 Value >>= 8; 184 } 185 break; 186 } 187 case macho::RIT_ARM_Branch24Bit: { 188 // Mask the value into the target address. We know instructions are 189 // 32-bit aligned, so we can do it all at once. 190 uint32_t *p = (uint32_t*)LocalAddress; 191 // The low two bits of the value are not encoded. 192 Value >>= 2; 193 // Mask the value to 24 bits. 194 Value &= 0xffffff; 195 // FIXME: If the destination is a Thumb function (and the instruction 196 // is a non-predicated BL instruction), we need to change it to a BLX 197 // instruction instead. 198 199 // Insert the value into the instruction. 200 *p = (*p & ~0xffffff) | Value; 201 break; 202 } 203 case macho::RIT_ARM_ThumbBranch22Bit: 204 case macho::RIT_ARM_ThumbBranch32Bit: 205 case macho::RIT_ARM_Half: 206 case macho::RIT_ARM_HalfDifference: 207 case macho::RIT_Pair: 208 case macho::RIT_Difference: 209 case macho::RIT_ARM_LocalDifference: 210 case macho::RIT_ARM_PreboundLazyPointer: 211 return Error("Relocation type not implemented yet!"); 212 } 213 return false; 214} 215 216void RuntimeDyldMachO::processRelocationRef(unsigned SectionID, 217 RelocationRef RelI, 218 ObjectImage &Obj, 219 ObjSectionToIDMap &ObjSectionToID, 220 const SymbolTableMap &Symbols, 221 StubMap &Stubs) { 222 const ObjectFile *OF = Obj.getObjectFile(); 223 const MachOObjectFile *MachO = static_cast<const MachOObjectFile*>(OF); 224 macho::RelocationEntry RE = MachO->getRelocation(RelI.getRawDataRefImpl()); 225 226 uint32_t RelType = MachO->getAnyRelocationType(RE); 227 RelocationValueRef Value; 228 SectionEntry &Section = Sections[SectionID]; 229 230 bool isExtern = MachO->getPlainRelocationExternal(RE); 231 bool IsPCRel = MachO->getAnyRelocationPCRel(RE); 232 unsigned Size = MachO->getAnyRelocationLength(RE); 233 if (isExtern) { 234 // Obtain the symbol name which is referenced in the relocation 235 SymbolRef Symbol; 236 RelI.getSymbol(Symbol); 237 StringRef TargetName; 238 Symbol.getName(TargetName); 239 // First search for the symbol in the local symbol table 240 SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data()); 241 if (lsi != Symbols.end()) { 242 Value.SectionID = lsi->second.first; 243 Value.Addend = lsi->second.second; 244 } else { 245 // Search for the symbol in the global symbol table 246 SymbolTableMap::const_iterator gsi = GlobalSymbolTable.find(TargetName.data()); 247 if (gsi != GlobalSymbolTable.end()) { 248 Value.SectionID = gsi->second.first; 249 Value.Addend = gsi->second.second; 250 } else 251 Value.SymbolName = TargetName.data(); 252 } 253 } else { 254 error_code err; 255 uint8_t sectionIndex = static_cast<uint8_t>(RelType & 0xFF); 256 section_iterator si = Obj.begin_sections(), 257 se = Obj.end_sections(); 258 for (uint8_t i = 1; i < sectionIndex; i++) { 259 error_code err; 260 si.increment(err); 261 if (si == se) 262 break; 263 } 264 assert(si != se && "No section containing relocation!"); 265 Value.SectionID = findOrEmitSection(Obj, *si, true, ObjSectionToID); 266 Value.Addend = 0; 267 // FIXME: The size and type of the relocation determines if we can 268 // encode an Addend in the target location itself, and if so, how many 269 // bytes we should read in order to get it. We don't yet support doing 270 // that, and just assuming it's sizeof(intptr_t) is blatantly wrong. 271 //Value.Addend = *(const intptr_t *)Target; 272 if (Value.Addend) { 273 // The MachO addend is an offset from the current section. We need it 274 // to be an offset from the destination section 275 Value.Addend += Section.ObjAddress - Sections[Value.SectionID].ObjAddress; 276 } 277 } 278 279 uint64_t Offset; 280 RelI.getOffset(Offset); 281 if (Arch == Triple::arm && (RelType & 0xf) == macho::RIT_ARM_Branch24Bit) { 282 // This is an ARM branch relocation, need to use a stub function. 283 284 // Look up for existing stub. 285 StubMap::const_iterator i = Stubs.find(Value); 286 if (i != Stubs.end()) 287 resolveRelocation(Section, Offset, 288 (uint64_t)Section.Address + i->second, 289 RelType, 0, IsPCRel, Size); 290 else { 291 // Create a new stub function. 292 Stubs[Value] = Section.StubOffset; 293 uint8_t *StubTargetAddr = createStubFunction(Section.Address + 294 Section.StubOffset); 295 RelocationEntry RE(SectionID, StubTargetAddr - Section.Address, 296 macho::RIT_Vanilla, Value.Addend); 297 if (Value.SymbolName) 298 addRelocationForSymbol(RE, Value.SymbolName); 299 else 300 addRelocationForSection(RE, Value.SectionID); 301 resolveRelocation(Section, Offset, 302 (uint64_t)Section.Address + Section.StubOffset, 303 RelType, 0, IsPCRel, Size); 304 Section.StubOffset += getMaxStubSize(); 305 } 306 } else { 307 RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, 308 IsPCRel, Size); 309 if (Value.SymbolName) 310 addRelocationForSymbol(RE, Value.SymbolName); 311 else 312 addRelocationForSection(RE, Value.SectionID); 313 } 314} 315 316 317bool RuntimeDyldMachO::isCompatibleFormat( 318 const ObjectBuffer *InputBuffer) const { 319 if (InputBuffer->getBufferSize() < 4) 320 return false; 321 StringRef Magic(InputBuffer->getBufferStart(), 4); 322 if (Magic == "\xFE\xED\xFA\xCE") return true; 323 if (Magic == "\xCE\xFA\xED\xFE") return true; 324 if (Magic == "\xFE\xED\xFA\xCF") return true; 325 if (Magic == "\xCF\xFA\xED\xFE") return true; 326 return false; 327} 328 329} // end namespace llvm 330