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