blob: 24437e0f96313061d61e26e9db2c24a65f37094a [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 Malyshev799184d2012-03-21 21:06:29 +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
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
Danil Malyshevcf852dc2011-07-13 07:57:58 +000042 // This just dispatches to the proper target specific routine.
Danil Malyshev799184d2012-03-21 21:06:29 +000043 switch (Arch) {
Craig Topper85814382012-02-07 05:05:23 +000044 default: llvm_unreachable("Unsupported CPU type!");
Danil Malyshev799184d2012-03-21 21:06:29 +000045 case Triple::x86_64: // Fall through.
46 case Triple::x86:
47 resolveX86_64Relocation(LocalAddress,
48 FinalAddress,
49 (uintptr_t)Value,
50 isPCRel,
51 MachoType,
52 Size,
53 Addend);
54 break;
55 case Triple::arm: // Fall through.
56 case Triple::thumb:
57 resolveARMRelocation(LocalAddress,
58 FinalAddress,
59 (uintptr_t)Value,
60 isPCRel,
61 MachoType,
62 Size,
63 Addend);
64 break;
Danil Malyshevcf852dc2011-07-13 07:57:58 +000065 }
Danil Malyshevcf852dc2011-07-13 07:57:58 +000066}
67
68bool RuntimeDyldMachO::
Sean Callanan61dfa772012-03-07 23:05:25 +000069resolveX86_64Relocation(uint8_t *LocalAddress,
70 uint64_t FinalAddress,
71 uint64_t Value,
72 bool isPCRel,
73 unsigned Type,
74 unsigned Size,
75 int64_t Addend) {
Danil Malyshevcf852dc2011-07-13 07:57:58 +000076 // If the relocation is PC-relative, the value to be encoded is the
77 // pointer difference.
78 if (isPCRel)
79 // FIXME: It seems this value needs to be adjusted by 4 for an effective PC
80 // address. Is that expected? Only for branches, perhaps?
Sean Callanan61dfa772012-03-07 23:05:25 +000081 Value -= FinalAddress + 4;
Danil Malyshevcf852dc2011-07-13 07:57:58 +000082
83 switch(Type) {
84 default:
85 llvm_unreachable("Invalid relocation type!");
Jim Grosbach652ca2f2012-01-16 23:50:49 +000086 case macho::RIT_X86_64_Signed1:
87 case macho::RIT_X86_64_Signed2:
88 case macho::RIT_X86_64_Signed4:
89 case macho::RIT_X86_64_Signed:
Danil Malyshevcf852dc2011-07-13 07:57:58 +000090 case macho::RIT_X86_64_Unsigned:
91 case macho::RIT_X86_64_Branch: {
Jim Grosbach652ca2f2012-01-16 23:50:49 +000092 Value += Addend;
Danil Malyshevcf852dc2011-07-13 07:57:58 +000093 // Mask in the target value a byte at a time (we don't have an alignment
94 // guarantee for the target address, so this is safest).
Sean Callanan61dfa772012-03-07 23:05:25 +000095 uint8_t *p = (uint8_t*)LocalAddress;
Danil Malyshevcf852dc2011-07-13 07:57:58 +000096 for (unsigned i = 0; i < Size; ++i) {
97 *p++ = (uint8_t)Value;
98 Value >>= 8;
99 }
100 return false;
101 }
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000102 case macho::RIT_X86_64_GOTLoad:
103 case macho::RIT_X86_64_GOT:
104 case macho::RIT_X86_64_Subtractor:
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000105 case macho::RIT_X86_64_TLV:
106 return Error("Relocation type not implemented yet!");
107 }
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000108}
109
Jim Grosbach61425c02012-01-16 22:26:39 +0000110bool RuntimeDyldMachO::
Sean Callanan61dfa772012-03-07 23:05:25 +0000111resolveARMRelocation(uint8_t *LocalAddress,
112 uint64_t FinalAddress,
113 uint64_t Value,
114 bool isPCRel,
115 unsigned Type,
116 unsigned Size,
117 int64_t Addend) {
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000118 // If the relocation is PC-relative, the value to be encoded is the
119 // pointer difference.
120 if (isPCRel) {
Sean Callanan61dfa772012-03-07 23:05:25 +0000121 Value -= FinalAddress;
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000122 // ARM PCRel relocations have an effective-PC offset of two instructions
123 // (four bytes in Thumb mode, 8 bytes in ARM mode).
124 // FIXME: For now, assume ARM mode.
125 Value -= 8;
126 }
127
128 switch(Type) {
129 default:
130 llvm_unreachable("Invalid relocation type!");
131 case macho::RIT_Vanilla: {
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000132 // Mask in the target value a byte at a time (we don't have an alignment
133 // guarantee for the target address, so this is safest).
Sean Callanan61dfa772012-03-07 23:05:25 +0000134 uint8_t *p = (uint8_t*)LocalAddress;
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000135 for (unsigned i = 0; i < Size; ++i) {
136 *p++ = (uint8_t)Value;
137 Value >>= 8;
138 }
139 break;
140 }
141 case macho::RIT_ARM_Branch24Bit: {
142 // Mask the value into the target address. We know instructions are
143 // 32-bit aligned, so we can do it all at once.
Sean Callanan61dfa772012-03-07 23:05:25 +0000144 uint32_t *p = (uint32_t*)LocalAddress;
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000145 // The low two bits of the value are not encoded.
146 Value >>= 2;
147 // Mask the value to 24 bits.
148 Value &= 0xffffff;
149 // FIXME: If the destination is a Thumb function (and the instruction
150 // is a non-predicated BL instruction), we need to change it to a BLX
151 // instruction instead.
152
153 // Insert the value into the instruction.
154 *p = (*p & ~0xffffff) | Value;
155 break;
156 }
157 case macho::RIT_ARM_ThumbBranch22Bit:
158 case macho::RIT_ARM_ThumbBranch32Bit:
159 case macho::RIT_ARM_Half:
160 case macho::RIT_ARM_HalfDifference:
161 case macho::RIT_Pair:
162 case macho::RIT_Difference:
163 case macho::RIT_ARM_LocalDifference:
164 case macho::RIT_ARM_PreboundLazyPointer:
165 return Error("Relocation type not implemented yet!");
166 }
167 return false;
168}
169
Danil Malyshev799184d2012-03-21 21:06:29 +0000170void RuntimeDyldMachO::
171processRelocationRef(const ObjRelocationInfo &Rel, const ObjectFile &Obj,
172 ObjSectionToIDMap &ObjSectionToID,
173 LocalSymbolMap &Symbols, StubMap &Stubs) {
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000174
Danil Malyshev799184d2012-03-21 21:06:29 +0000175 uint32_t RelType = (uint32_t) (Rel.Type & 0xffffffffL);
176 RelocationValueRef Value;
177 SectionEntry &Section = Sections[Rel.SectionID];
178 uint8_t *Target = Section.Address + Rel.Offset;
Jim Grosbach61425c02012-01-16 22:26:39 +0000179
Danil Malyshev799184d2012-03-21 21:06:29 +0000180 bool isExtern = (RelType >> 27) & 1;
181 if (isExtern) {
182 StringRef TargetName;
183 const SymbolRef &Symbol = Rel.Symbol;
184 Symbol.getName(TargetName);
185 // First look the symbol in object file symbols.
186 LocalSymbolMap::iterator it = Symbols.find(TargetName.data());
187 if (it != Symbols.end()) {
188 Value.SectionID = it->second.first;
189 Value.Addend = it->second.second;
190 } else {
191 // Second look the symbol in global symbol table.
192 StringMap<SymbolLoc>::iterator itS = SymbolTable.find(TargetName.data());
193 if (itS != SymbolTable.end()) {
194 Value.SectionID = itS->second.first;
195 Value.Addend = itS->second.second;
196 } else
197 Value.SymbolName = TargetName.data();
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000198 }
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000199 } else {
Danil Malyshev799184d2012-03-21 21:06:29 +0000200 error_code err;
201 uint8_t sIdx = static_cast<uint8_t>(RelType & 0xFF);
202 section_iterator sIt = Obj.begin_sections(),
203 sItEnd = Obj.end_sections();
204 for (uint8_t i = 1; i < sIdx; i++) {
205 error_code err;
206 sIt.increment(err);
207 if (sIt == sItEnd)
208 break;
209 }
210 assert(sIt != sItEnd && "No section containing relocation!");
211 Value.SectionID = findOrEmitSection(*sIt, true, ObjSectionToID);
212 Value.Addend = *(const intptr_t *)Target;
213 if (Value.Addend) {
214 // The MachO addend is offset from the current section, we need set it
215 // as offset from destination section
216 Value.Addend += Section.ObjAddress - Sections[Value.SectionID].ObjAddress;
217 }
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000218 }
219
Danil Malyshev799184d2012-03-21 21:06:29 +0000220 if (Arch == Triple::arm && RelType == macho::RIT_ARM_Branch24Bit) {
221 // This is an ARM branch relocation, need to use a stub function.
Jim Grosbach61425c02012-01-16 22:26:39 +0000222
Danil Malyshev799184d2012-03-21 21:06:29 +0000223 // Look up for existing stub.
224 StubMap::const_iterator stubIt = Stubs.find(Value);
225 if (stubIt != Stubs.end())
226 resolveRelocation(Target, (uint64_t)Target,
227 (uint64_t)Section.Address + stubIt->second,
228 RelType, 0);
229 else {
230 // Create a new stub function.
231 Stubs[Value] = Section.StubOffset;
232 uint8_t *StubTargetAddr = createStubFunction(Section.Address +
233 Section.StubOffset);
234 AddRelocation(Value, Rel.SectionID, StubTargetAddr - Section.Address,
235 macho::RIT_Vanilla);
236 resolveRelocation(Target, (uint64_t)Target,
237 (uint64_t)Section.Address + Section.StubOffset,
238 RelType, 0);
239 Section.StubOffset += getMaxStubSize();
240 }
241 } else
242 AddRelocation(Value, Rel.SectionID, Rel.Offset, RelType);
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000243}
244
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000245
Danil Malyshev799184d2012-03-21 21:06:29 +0000246bool RuntimeDyldMachO::isCompatibleFormat(const MemoryBuffer *InputBuffer) const {
Danil Malyshevcf852dc2011-07-13 07:57:58 +0000247 StringRef Magic = InputBuffer->getBuffer().slice(0, 4);
248 if (Magic == "\xFE\xED\xFA\xCE") return true;
249 if (Magic == "\xCE\xFA\xED\xFE") return true;
250 if (Magic == "\xFE\xED\xFA\xCF") return true;
251 if (Magic == "\xCF\xFA\xED\xFE") return true;
252 return false;
253}
254
255} // end namespace llvm