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