RuntimeDyldMachO.cpp revision a307a1cf859f4a523951ac887d094039547adeb5
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(const SectionEntry &Section, 25 uint64_t Offset, 26 uint64_t Value, 27 uint32_t Type, 28 int64_t Addend) { 29 uint8_t *LocalAddress = Section.Address + Offset; 30 uint64_t FinalAddress = Section.LoadAddress + Offset; 31 bool isPCRel = (Type >> 24) & 1; 32 unsigned MachoType = (Type >> 28) & 0xf; 33 unsigned Size = 1 << ((Type >> 25) & 3); 34 35 DEBUG(dbgs() << "resolveRelocation LocalAddress: " 36 << format("%p", LocalAddress) 37 << " FinalAddress: " << format("%p", FinalAddress) 38 << " Value: " << format("%p", Value) 39 << " Addend: " << Addend 40 << " isPCRel: " << isPCRel 41 << " MachoType: " << MachoType 42 << " Size: " << Size 43 << "\n"); 44 45 // This just dispatches to the proper target specific routine. 46 switch (Arch) { 47 default: llvm_unreachable("Unsupported CPU type!"); 48 case Triple::x86_64: 49 resolveX86_64Relocation(LocalAddress, 50 FinalAddress, 51 (uintptr_t)Value, 52 isPCRel, 53 MachoType, 54 Size, 55 Addend); 56 break; 57 case Triple::x86: 58 resolveI386Relocation(LocalAddress, 59 FinalAddress, 60 (uintptr_t)Value, 61 isPCRel, 62 MachoType, 63 Size, 64 Addend); 65 break; 66 case Triple::arm: // Fall through. 67 case Triple::thumb: 68 resolveARMRelocation(LocalAddress, 69 FinalAddress, 70 (uintptr_t)Value, 71 isPCRel, 72 MachoType, 73 Size, 74 Addend); 75 break; 76 } 77} 78 79bool RuntimeDyldMachO::resolveI386Relocation(uint8_t *LocalAddress, 80 uint64_t FinalAddress, 81 uint64_t Value, 82 bool isPCRel, 83 unsigned Type, 84 unsigned Size, 85 int64_t Addend) { 86 if (isPCRel) 87 Value -= FinalAddress + 4; // see resolveX86_64Relocation 88 89 switch (Type) { 90 default: 91 llvm_unreachable("Invalid relocation type!"); 92 case macho::RIT_Vanilla: { 93 uint8_t *p = LocalAddress; 94 uint64_t ValueToWrite = Value + Addend; 95 for (unsigned i = 0; i < Size; ++i) { 96 *p++ = (uint8_t)(ValueToWrite & 0xff); 97 ValueToWrite >>= 8; 98 } 99 } 100 case macho::RIT_Difference: 101 case macho::RIT_Generic_LocalDifference: 102 case macho::RIT_Generic_PreboundLazyPointer: 103 return Error("Relocation type not implemented yet!"); 104 } 105} 106 107bool RuntimeDyldMachO::resolveX86_64Relocation(uint8_t *LocalAddress, 108 uint64_t FinalAddress, 109 uint64_t Value, 110 bool isPCRel, 111 unsigned Type, 112 unsigned Size, 113 int64_t Addend) { 114 // If the relocation is PC-relative, the value to be encoded is the 115 // pointer difference. 116 if (isPCRel) 117 // FIXME: It seems this value needs to be adjusted by 4 for an effective PC 118 // address. Is that expected? Only for branches, perhaps? 119 Value -= FinalAddress + 4; 120 121 switch(Type) { 122 default: 123 llvm_unreachable("Invalid relocation type!"); 124 case macho::RIT_X86_64_Signed1: 125 case macho::RIT_X86_64_Signed2: 126 case macho::RIT_X86_64_Signed4: 127 case macho::RIT_X86_64_Signed: 128 case macho::RIT_X86_64_Unsigned: 129 case macho::RIT_X86_64_Branch: { 130 Value += Addend; 131 // Mask in the target value a byte at a time (we don't have an alignment 132 // guarantee for the target address, so this is safest). 133 uint8_t *p = (uint8_t*)LocalAddress; 134 for (unsigned i = 0; i < Size; ++i) { 135 *p++ = (uint8_t)Value; 136 Value >>= 8; 137 } 138 return false; 139 } 140 case macho::RIT_X86_64_GOTLoad: 141 case macho::RIT_X86_64_GOT: 142 case macho::RIT_X86_64_Subtractor: 143 case macho::RIT_X86_64_TLV: 144 return Error("Relocation type not implemented yet!"); 145 } 146} 147 148bool RuntimeDyldMachO::resolveARMRelocation(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 ObjectImage &Obj, 209 ObjSectionToIDMap &ObjSectionToID, 210 const SymbolTableMap &Symbols, 211 StubMap &Stubs) { 212 213 uint32_t RelType = (uint32_t) (Rel.Type & 0xffffffffL); 214 RelocationValueRef Value; 215 SectionEntry &Section = Sections[Rel.SectionID]; 216 217 bool isExtern = (RelType >> 27) & 1; 218 if (isExtern) { 219 // Obtain the symbol name which is referenced in the relocation 220 StringRef TargetName; 221 const SymbolRef &Symbol = Rel.Symbol; 222 Symbol.getName(TargetName); 223 // First search for the symbol in the local symbol table 224 SymbolTableMap::const_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 // Search for the symbol in the global symbol table 230 SymbolTableMap::const_iterator gsi = GlobalSymbolTable.find(TargetName.data()); 231 if (gsi != GlobalSymbolTable.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(Obj, *si, true, ObjSectionToID); 250 Value.Addend = 0; 251 // FIXME: The size and type of the relocation determines if we can 252 // encode an Addend in the target location itself, and if so, how many 253 // bytes we should read in order to get it. We don't yet support doing 254 // that, and just assuming it's sizeof(intptr_t) is blatantly wrong. 255 //Value.Addend = *(const intptr_t *)Target; 256 if (Value.Addend) { 257 // The MachO addend is an offset from the current section. We need it 258 // to be an offset from the destination section 259 Value.Addend += Section.ObjAddress - Sections[Value.SectionID].ObjAddress; 260 } 261 } 262 263 if (Arch == Triple::arm && (RelType & 0xf) == macho::RIT_ARM_Branch24Bit) { 264 // This is an ARM branch relocation, need to use a stub function. 265 266 // Look up for existing stub. 267 StubMap::const_iterator i = Stubs.find(Value); 268 if (i != Stubs.end()) 269 resolveRelocation(Section, Rel.Offset, 270 (uint64_t)Section.Address + i->second, 271 RelType, 0); 272 else { 273 // Create a new stub function. 274 Stubs[Value] = Section.StubOffset; 275 uint8_t *StubTargetAddr = createStubFunction(Section.Address + 276 Section.StubOffset); 277 RelocationEntry RE(Rel.SectionID, StubTargetAddr - Section.Address, 278 macho::RIT_Vanilla, Value.Addend); 279 if (Value.SymbolName) 280 addRelocationForSymbol(RE, Value.SymbolName); 281 else 282 addRelocationForSection(RE, Value.SectionID); 283 resolveRelocation(Section, Rel.Offset, 284 (uint64_t)Section.Address + Section.StubOffset, 285 RelType, 0); 286 Section.StubOffset += getMaxStubSize(); 287 } 288 } else { 289 RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType, Value.Addend); 290 if (Value.SymbolName) 291 addRelocationForSymbol(RE, Value.SymbolName); 292 else 293 addRelocationForSection(RE, Value.SectionID); 294 } 295} 296 297 298bool RuntimeDyldMachO::isCompatibleFormat( 299 const ObjectBuffer *InputBuffer) const { 300 if (InputBuffer->getBufferSize() < 4) 301 return false; 302 StringRef Magic(InputBuffer->getBufferStart(), 4); 303 if (Magic == "\xFE\xED\xFA\xCE") return true; 304 if (Magic == "\xCE\xFA\xED\xFE") return true; 305 if (Magic == "\xFE\xED\xFA\xCF") return true; 306 if (Magic == "\xCF\xFA\xED\xFE") return true; 307 return false; 308} 309 310} // end namespace llvm 311