blob: 56540c23dac3b444b880bbe35aa3bf6816ba7023 [file] [log] [blame]
Jim Grosbache0934be2012-01-16 23:50:58 +00001//===-- RuntimeDyldMachO.cpp - Run-time dynamic linker for MC-JIT -*- C++ -*-=//
Danil Malyshevcf852dc2011-07-13 07:57:58 +00002//
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"
Eli Bendersky76463fd2012-01-22 07:05:02 +000018#include "RuntimeDyldMachO.h"
Danil Malyshevcf852dc2011-07-13 07:57:58 +000019using namespace llvm;
20using namespace llvm::object;
21
22namespace llvm {
23
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +000024void 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
Eli Bendersky6d15e872012-04-30 10:06:27 +000033 DEBUG(dbgs() << "resolveRelocation LocalAddress: "
34 << format("%p", LocalAddress)
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +000035 << " FinalAddress: " << format("%p", FinalAddress)
36 << " Value: " << format("%p", Value)
37 << " Addend: " << Addend
38 << " isPCRel: " << isPCRel
39 << " MachoType: " << MachoType
40 << " Size: " << Size
41 << "\n");
42
Danil Malyshevcf852dc2011-07-13 07:57:58 +000043 // This just dispatches to the proper target specific routine.
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +000044 switch (Arch) {
Craig Topper85814382012-02-07 05:05:23 +000045 default: llvm_unreachable("Unsupported CPU type!");
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +000046 case Triple::x86_64:
47 resolveX86_64Relocation(LocalAddress,
48 FinalAddress,
49 (uintptr_t)Value,
50 isPCRel,
51 MachoType,
52 Size,
53 Addend);
54 break;
55 case Triple::x86:
56 resolveI386Relocation(LocalAddress,
Eli Bendersky6d15e872012-04-30 10:06:27 +000057 FinalAddress,
58 (uintptr_t)Value,
59 isPCRel,
Jim Grosbachba9ba9f2012-09-13 01:24:32 +000060 MachoType,
Eli Bendersky6d15e872012-04-30 10:06:27 +000061 Size,
62 Addend);
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +000063 break;
64 case Triple::arm: // Fall through.
65 case Triple::thumb:
66 resolveARMRelocation(LocalAddress,
67 FinalAddress,
68 (uintptr_t)Value,
69 isPCRel,
70 MachoType,
71 Size,
72 Addend);
73 break;
Danil Malyshevcf852dc2011-07-13 07:57:58 +000074 }
Danil Malyshevcf852dc2011-07-13 07:57:58 +000075}
76
Eli Bendersky6d15e872012-04-30 10:06:27 +000077bool RuntimeDyldMachO::resolveI386Relocation(uint8_t *LocalAddress,
78 uint64_t FinalAddress,
79 uint64_t Value,
80 bool isPCRel,
81 unsigned Type,
82 unsigned Size,
83 int64_t Addend) {
Sean Callananb38aae42012-03-26 20:45:52 +000084 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
Eli Bendersky6d15e872012-04-30 10:06:27 +0000105bool RuntimeDyldMachO::resolveX86_64Relocation(uint8_t *LocalAddress,
106 uint64_t FinalAddress,
107 uint64_t Value,
108 bool isPCRel,
109 unsigned Type,
110 unsigned Size,
111 int64_t Addend) {
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000112 // If the relocation is PC-relative, the value to be encoded is the
113 // pointer difference.
114 if (isPCRel)
115 // FIXME: It seems this value needs to be adjusted by 4 for an effective PC
116 // address. Is that expected? Only for branches, perhaps?
Sean Callanan61dfa772012-03-07 23:05:25 +0000117 Value -= FinalAddress + 4;
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000118
119 switch(Type) {
120 default:
121 llvm_unreachable("Invalid relocation type!");
Jim Grosbach652ca2f2012-01-16 23:50:49 +0000122 case macho::RIT_X86_64_Signed1:
123 case macho::RIT_X86_64_Signed2:
124 case macho::RIT_X86_64_Signed4:
125 case macho::RIT_X86_64_Signed:
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000126 case macho::RIT_X86_64_Unsigned:
127 case macho::RIT_X86_64_Branch: {
Jim Grosbach652ca2f2012-01-16 23:50:49 +0000128 Value += Addend;
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000129 // Mask in the target value a byte at a time (we don't have an alignment
130 // guarantee for the target address, so this is safest).
Sean Callanan61dfa772012-03-07 23:05:25 +0000131 uint8_t *p = (uint8_t*)LocalAddress;
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000132 for (unsigned i = 0; i < Size; ++i) {
133 *p++ = (uint8_t)Value;
134 Value >>= 8;
135 }
136 return false;
137 }
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000138 case macho::RIT_X86_64_GOTLoad:
139 case macho::RIT_X86_64_GOT:
140 case macho::RIT_X86_64_Subtractor:
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000141 case macho::RIT_X86_64_TLV:
142 return Error("Relocation type not implemented yet!");
143 }
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000144}
145
Eli Bendersky6d15e872012-04-30 10:06:27 +0000146bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress,
147 uint64_t FinalAddress,
148 uint64_t Value,
149 bool isPCRel,
150 unsigned Type,
151 unsigned Size,
152 int64_t Addend) {
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000153 // If the relocation is PC-relative, the value to be encoded is the
154 // pointer difference.
155 if (isPCRel) {
Sean Callanan61dfa772012-03-07 23:05:25 +0000156 Value -= FinalAddress;
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000157 // ARM PCRel relocations have an effective-PC offset of two instructions
158 // (four bytes in Thumb mode, 8 bytes in ARM mode).
159 // FIXME: For now, assume ARM mode.
160 Value -= 8;
161 }
162
163 switch(Type) {
164 default:
165 llvm_unreachable("Invalid relocation type!");
166 case macho::RIT_Vanilla: {
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000167 // Mask in the target value a byte at a time (we don't have an alignment
168 // guarantee for the target address, so this is safest).
Sean Callanan61dfa772012-03-07 23:05:25 +0000169 uint8_t *p = (uint8_t*)LocalAddress;
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000170 for (unsigned i = 0; i < Size; ++i) {
171 *p++ = (uint8_t)Value;
172 Value >>= 8;
173 }
174 break;
175 }
176 case macho::RIT_ARM_Branch24Bit: {
177 // Mask the value into the target address. We know instructions are
178 // 32-bit aligned, so we can do it all at once.
Sean Callanan61dfa772012-03-07 23:05:25 +0000179 uint32_t *p = (uint32_t*)LocalAddress;
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000180 // The low two bits of the value are not encoded.
181 Value >>= 2;
182 // Mask the value to 24 bits.
183 Value &= 0xffffff;
184 // FIXME: If the destination is a Thumb function (and the instruction
185 // is a non-predicated BL instruction), we need to change it to a BLX
186 // instruction instead.
187
188 // Insert the value into the instruction.
189 *p = (*p & ~0xffffff) | Value;
190 break;
191 }
192 case macho::RIT_ARM_ThumbBranch22Bit:
193 case macho::RIT_ARM_ThumbBranch32Bit:
194 case macho::RIT_ARM_Half:
195 case macho::RIT_ARM_HalfDifference:
196 case macho::RIT_Pair:
197 case macho::RIT_Difference:
198 case macho::RIT_ARM_LocalDifference:
199 case macho::RIT_ARM_PreboundLazyPointer:
200 return Error("Relocation type not implemented yet!");
201 }
202 return false;
203}
204
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000205void RuntimeDyldMachO::processRelocationRef(const ObjRelocationInfo &Rel,
Preston Gurd689ff9c2012-04-16 22:12:58 +0000206 ObjectImage &Obj,
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000207 ObjSectionToIDMap &ObjSectionToID,
Eli Benderskyd98c9e92012-05-01 06:58:59 +0000208 const SymbolTableMap &Symbols,
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000209 StubMap &Stubs) {
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000210
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000211 uint32_t RelType = (uint32_t) (Rel.Type & 0xffffffffL);
212 RelocationValueRef Value;
213 SectionEntry &Section = Sections[Rel.SectionID];
214 uint8_t *Target = Section.Address + Rel.Offset;
Jim Grosbach61425c02012-01-16 22:26:39 +0000215
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000216 bool isExtern = (RelType >> 27) & 1;
217 if (isExtern) {
Eli Benderskyc201e6e2012-05-01 10:41:12 +0000218 // Obtain the symbol name which is referenced in the relocation
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000219 StringRef TargetName;
220 const SymbolRef &Symbol = Rel.Symbol;
221 Symbol.getName(TargetName);
Eli Benderskyc201e6e2012-05-01 10:41:12 +0000222 // First search for the symbol in the local symbol table
Eli Benderskyd98c9e92012-05-01 06:58:59 +0000223 SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data());
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000224 if (lsi != Symbols.end()) {
225 Value.SectionID = lsi->second.first;
226 Value.Addend = lsi->second.second;
227 } else {
Eli Benderskyc201e6e2012-05-01 10:41:12 +0000228 // Search for the symbol in the global symbol table
Eli Benderskyd98c9e92012-05-01 06:58:59 +0000229 SymbolTableMap::const_iterator gsi = GlobalSymbolTable.find(TargetName.data());
230 if (gsi != GlobalSymbolTable.end()) {
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000231 Value.SectionID = gsi->second.first;
232 Value.Addend = gsi->second.second;
233 } else
234 Value.SymbolName = TargetName.data();
Danil Malyshev4b0b8ef2012-03-29 21:46:18 +0000235 }
Bill Wendling288967d2012-03-29 23:23:59 +0000236 } else {
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000237 error_code err;
238 uint8_t sectionIndex = static_cast<uint8_t>(RelType & 0xFF);
239 section_iterator si = Obj.begin_sections(),
240 se = Obj.end_sections();
241 for (uint8_t i = 1; i < sectionIndex; i++) {
242 error_code err;
243 si.increment(err);
244 if (si == se)
245 break;
246 }
247 assert(si != se && "No section containing relocation!");
Preston Gurd689ff9c2012-04-16 22:12:58 +0000248 Value.SectionID = findOrEmitSection(Obj, *si, true, ObjSectionToID);
Jim Grosbach7639f982012-09-13 01:24:37 +0000249 Value.Addend = 0;
250 // FIXME: The size and type of the relocation determines if we can
251 // encode an Addend in the target location itself, and if so, how many
252 // bytes we should read in order to get it. We don't yet support doing
253 // that, and just assuming it's sizeof(intptr_t) is blatantly wrong.
254 //Value.Addend = *(const intptr_t *)Target;
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000255 if (Value.Addend) {
Eli Benderskyc201e6e2012-05-01 10:41:12 +0000256 // The MachO addend is an offset from the current section. We need it
257 // to be an offset from the destination section
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000258 Value.Addend += Section.ObjAddress - Sections[Value.SectionID].ObjAddress;
259 }
Bill Wendling288967d2012-03-29 23:23:59 +0000260 }
261
Jim Grosbach01e1a972012-09-13 01:24:35 +0000262 if (Arch == Triple::arm && (RelType & 0xf) == macho::RIT_ARM_Branch24Bit) {
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000263 // This is an ARM branch relocation, need to use a stub function.
Bill Wendling288967d2012-03-29 23:23:59 +0000264
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000265 // Look up for existing stub.
266 StubMap::const_iterator i = Stubs.find(Value);
267 if (i != Stubs.end())
268 resolveRelocation(Target, (uint64_t)Target,
269 (uint64_t)Section.Address + i->second,
270 RelType, 0);
271 else {
272 // Create a new stub function.
273 Stubs[Value] = Section.StubOffset;
274 uint8_t *StubTargetAddr = createStubFunction(Section.Address +
275 Section.StubOffset);
Eli Benderskyc201e6e2012-05-01 10:41:12 +0000276 RelocationEntry RE(Rel.SectionID, StubTargetAddr - Section.Address,
277 macho::RIT_Vanilla, Value.Addend);
278 if (Value.SymbolName)
279 addRelocationForSymbol(RE, Value.SymbolName);
280 else
281 addRelocationForSection(RE, Value.SectionID);
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000282 resolveRelocation(Target, (uint64_t)Target,
283 (uint64_t)Section.Address + Section.StubOffset,
284 RelType, 0);
285 Section.StubOffset += getMaxStubSize();
286 }
Eli Benderskyc201e6e2012-05-01 10:41:12 +0000287 } else {
288 RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType, Value.Addend);
289 if (Value.SymbolName)
290 addRelocationForSymbol(RE, Value.SymbolName);
291 else
292 addRelocationForSection(RE, Value.SectionID);
293 }
Bill Wendling288967d2012-03-29 23:23:59 +0000294}
295
Bill Wendling288967d2012-03-29 23:23:59 +0000296
Eli Bendersky6d15e872012-04-30 10:06:27 +0000297bool RuntimeDyldMachO::isCompatibleFormat(
Andrew Kaylor3f23cef2012-10-02 21:18:39 +0000298 const ObjectBuffer *InputBuffer) const {
299 if (InputBuffer->getBufferSize() < 4)
300 return false;
301 StringRef Magic(InputBuffer->getBufferStart(), 4);
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000302 if (Magic == "\xFE\xED\xFA\xCE") return true;
303 if (Magic == "\xCE\xFA\xED\xFE") return true;
304 if (Magic == "\xFE\xED\xFA\xCF") return true;
305 if (Magic == "\xCF\xFA\xED\xFE") return true;
306 return false;
307}
308
309} // end namespace llvm