blob: a9574eb0ba77a1620421992460f15cd6b662acee [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,
60 Type,
61 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,
208 LocalSymbolMap &Symbols,
209 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) {
218 StringRef TargetName;
219 const SymbolRef &Symbol = Rel.Symbol;
220 Symbol.getName(TargetName);
221 // First look the symbol in object file symbols.
222 LocalSymbolMap::iterator lsi = Symbols.find(TargetName.data());
223 if (lsi != Symbols.end()) {
224 Value.SectionID = lsi->second.first;
225 Value.Addend = lsi->second.second;
226 } else {
227 // Second look the symbol in global symbol table.
228 StringMap<SymbolLoc>::iterator gsi = SymbolTable.find(TargetName.data());
229 if (gsi != SymbolTable.end()) {
230 Value.SectionID = gsi->second.first;
231 Value.Addend = gsi->second.second;
232 } else
233 Value.SymbolName = TargetName.data();
Danil Malyshev4b0b8ef2012-03-29 21:46:18 +0000234 }
Bill Wendling288967d2012-03-29 23:23:59 +0000235 } else {
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000236 error_code err;
237 uint8_t sectionIndex = static_cast<uint8_t>(RelType & 0xFF);
238 section_iterator si = Obj.begin_sections(),
239 se = Obj.end_sections();
240 for (uint8_t i = 1; i < sectionIndex; i++) {
241 error_code err;
242 si.increment(err);
243 if (si == se)
244 break;
245 }
246 assert(si != se && "No section containing relocation!");
Preston Gurd689ff9c2012-04-16 22:12:58 +0000247 Value.SectionID = findOrEmitSection(Obj, *si, true, ObjSectionToID);
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000248 Value.Addend = *(const intptr_t *)Target;
249 if (Value.Addend) {
250 // The MachO addend is offset from the current section, we need set it
251 // as offset from destination section
252 Value.Addend += Section.ObjAddress - Sections[Value.SectionID].ObjAddress;
253 }
Bill Wendling288967d2012-03-29 23:23:59 +0000254 }
255
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000256 if (Arch == Triple::arm && RelType == macho::RIT_ARM_Branch24Bit) {
257 // This is an ARM branch relocation, need to use a stub function.
Bill Wendling288967d2012-03-29 23:23:59 +0000258
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000259 // Look up for existing stub.
260 StubMap::const_iterator i = Stubs.find(Value);
261 if (i != Stubs.end())
262 resolveRelocation(Target, (uint64_t)Target,
263 (uint64_t)Section.Address + i->second,
264 RelType, 0);
265 else {
266 // Create a new stub function.
267 Stubs[Value] = Section.StubOffset;
268 uint8_t *StubTargetAddr = createStubFunction(Section.Address +
269 Section.StubOffset);
Eli Bendersky6d15e872012-04-30 10:06:27 +0000270 addRelocation(Value, Rel.SectionID, StubTargetAddr - Section.Address,
Danil Malyshev0e4fa5f2012-03-30 16:45:19 +0000271 macho::RIT_Vanilla);
272 resolveRelocation(Target, (uint64_t)Target,
273 (uint64_t)Section.Address + Section.StubOffset,
274 RelType, 0);
275 Section.StubOffset += getMaxStubSize();
276 }
277 } else
Eli Bendersky6d15e872012-04-30 10:06:27 +0000278 addRelocation(Value, Rel.SectionID, Rel.Offset, RelType);
Bill Wendling288967d2012-03-29 23:23:59 +0000279}
280
Bill Wendling288967d2012-03-29 23:23:59 +0000281
Eli Bendersky6d15e872012-04-30 10:06:27 +0000282bool RuntimeDyldMachO::isCompatibleFormat(
283 const MemoryBuffer *InputBuffer) const {
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000284 StringRef Magic = InputBuffer->getBuffer().slice(0, 4);
285 if (Magic == "\xFE\xED\xFA\xCE") return true;
286 if (Magic == "\xCE\xFA\xED\xFE") return true;
287 if (Magic == "\xFE\xED\xFA\xCF") return true;
288 if (Magic == "\xCF\xFA\xED\xFE") return true;
289 return false;
290}
291
292} // end namespace llvm