RuntimeDyldMachO.cpp revision 251662
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
24static unsigned char *processFDE(unsigned char *P, intptr_t DeltaForText, intptr_t DeltaForEH) {
25  uint32_t Length = *((uint32_t*)P);
26  P += 4;
27  unsigned char *Ret = P + Length;
28  uint32_t Offset = *((uint32_t*)P);
29  if (Offset == 0) // is a CIE
30    return Ret;
31
32  P += 4;
33  intptr_t FDELocation = *((intptr_t*)P);
34  intptr_t NewLocation = FDELocation - DeltaForText;
35  *((intptr_t*)P) = NewLocation;
36  P += sizeof(intptr_t);
37
38  // Skip the FDE address range
39  P += sizeof(intptr_t);
40
41  uint8_t Augmentationsize = *P;
42  P += 1;
43  if (Augmentationsize != 0) {
44    intptr_t LSDA = *((intptr_t*)P);
45    intptr_t NewLSDA = LSDA - DeltaForEH;
46    *((intptr_t*)P) = NewLSDA;
47  }
48
49  return Ret;
50}
51
52static intptr_t computeDelta(SectionEntry *A, SectionEntry *B) {
53  intptr_t ObjDistance = A->ObjAddress  - B->ObjAddress;
54  intptr_t MemDistance = A->LoadAddress - B->LoadAddress;
55  return ObjDistance - MemDistance;
56}
57
58StringRef RuntimeDyldMachO::getEHFrameSection() {
59  SectionEntry *Text = NULL;
60  SectionEntry *EHFrame = NULL;
61  SectionEntry *ExceptTab = NULL;
62  for (int i = 0, e = Sections.size(); i != e; ++i) {
63    if (Sections[i].Name == "__eh_frame")
64      EHFrame = &Sections[i];
65    else if (Sections[i].Name == "__text")
66      Text = &Sections[i];
67    else if (Sections[i].Name == "__gcc_except_tab")
68      ExceptTab = &Sections[i];
69  }
70  if (Text == NULL || EHFrame == NULL)
71    return StringRef();
72
73  intptr_t DeltaForText = computeDelta(Text, EHFrame);
74  intptr_t DeltaForEH = 0;
75  if (ExceptTab)
76    DeltaForEH = computeDelta(ExceptTab, EHFrame);
77
78  unsigned char *P = EHFrame->Address;
79  unsigned char *End = P + EHFrame->Size;
80  do  {
81    P = processFDE(P, DeltaForText, DeltaForEH);
82  } while(P != End);
83
84  return StringRef((char*)EHFrame->Address, EHFrame->Size);
85}
86
87void RuntimeDyldMachO::resolveRelocation(const RelocationEntry &RE,
88                                         uint64_t Value) {
89  const SectionEntry &Section = Sections[RE.SectionID];
90  return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend,
91                           RE.IsPCRel, RE.Size);
92}
93
94void RuntimeDyldMachO::resolveRelocation(const SectionEntry &Section,
95                                         uint64_t Offset,
96                                         uint64_t Value,
97                                         uint32_t Type,
98                                         int64_t Addend,
99                                         bool isPCRel,
100                                         unsigned LogSize) {
101  uint8_t *LocalAddress = Section.Address + Offset;
102  uint64_t FinalAddress = Section.LoadAddress + Offset;
103  unsigned MachoType = Type;
104  unsigned Size = 1 << LogSize;
105
106  DEBUG(dbgs() << "resolveRelocation LocalAddress: "
107        << format("%p", LocalAddress)
108        << " FinalAddress: " << format("%p", FinalAddress)
109        << " Value: " << format("%p", Value)
110        << " Addend: " << Addend
111        << " isPCRel: " << isPCRel
112        << " MachoType: " << MachoType
113        << " Size: " << Size
114        << "\n");
115
116  // This just dispatches to the proper target specific routine.
117  switch (Arch) {
118  default: llvm_unreachable("Unsupported CPU type!");
119  case Triple::x86_64:
120    resolveX86_64Relocation(LocalAddress,
121                            FinalAddress,
122                            (uintptr_t)Value,
123                            isPCRel,
124                            MachoType,
125                            Size,
126                            Addend);
127    break;
128  case Triple::x86:
129    resolveI386Relocation(LocalAddress,
130                          FinalAddress,
131                          (uintptr_t)Value,
132                          isPCRel,
133                          MachoType,
134                          Size,
135                          Addend);
136    break;
137  case Triple::arm:    // Fall through.
138  case Triple::thumb:
139    resolveARMRelocation(LocalAddress,
140                         FinalAddress,
141                         (uintptr_t)Value,
142                         isPCRel,
143                         MachoType,
144                         Size,
145                         Addend);
146    break;
147  }
148}
149
150bool RuntimeDyldMachO::resolveI386Relocation(uint8_t *LocalAddress,
151                                             uint64_t FinalAddress,
152                                             uint64_t Value,
153                                             bool isPCRel,
154                                             unsigned Type,
155                                             unsigned Size,
156                                             int64_t Addend) {
157  if (isPCRel)
158    Value -= FinalAddress + 4; // see resolveX86_64Relocation
159
160  switch (Type) {
161  default:
162    llvm_unreachable("Invalid relocation type!");
163  case macho::RIT_Vanilla: {
164    uint8_t *p = LocalAddress;
165    uint64_t ValueToWrite = Value + Addend;
166    for (unsigned i = 0; i < Size; ++i) {
167      *p++ = (uint8_t)(ValueToWrite & 0xff);
168      ValueToWrite >>= 8;
169    }
170    return false;
171  }
172  case macho::RIT_Difference:
173  case macho::RIT_Generic_LocalDifference:
174  case macho::RIT_Generic_PreboundLazyPointer:
175    return Error("Relocation type not implemented yet!");
176  }
177}
178
179bool RuntimeDyldMachO::resolveX86_64Relocation(uint8_t *LocalAddress,
180                                               uint64_t FinalAddress,
181                                               uint64_t Value,
182                                               bool isPCRel,
183                                               unsigned Type,
184                                               unsigned Size,
185                                               int64_t Addend) {
186  // If the relocation is PC-relative, the value to be encoded is the
187  // pointer difference.
188  if (isPCRel)
189    // FIXME: It seems this value needs to be adjusted by 4 for an effective PC
190    // address. Is that expected? Only for branches, perhaps?
191    Value -= FinalAddress + 4;
192
193  switch(Type) {
194  default:
195    llvm_unreachable("Invalid relocation type!");
196  case macho::RIT_X86_64_Signed1:
197  case macho::RIT_X86_64_Signed2:
198  case macho::RIT_X86_64_Signed4:
199  case macho::RIT_X86_64_Signed:
200  case macho::RIT_X86_64_Unsigned:
201  case macho::RIT_X86_64_Branch: {
202    Value += Addend;
203    // Mask in the target value a byte at a time (we don't have an alignment
204    // guarantee for the target address, so this is safest).
205    uint8_t *p = (uint8_t*)LocalAddress;
206    for (unsigned i = 0; i < Size; ++i) {
207      *p++ = (uint8_t)Value;
208      Value >>= 8;
209    }
210    return false;
211  }
212  case macho::RIT_X86_64_GOTLoad:
213  case macho::RIT_X86_64_GOT:
214  case macho::RIT_X86_64_Subtractor:
215  case macho::RIT_X86_64_TLV:
216    return Error("Relocation type not implemented yet!");
217  }
218}
219
220bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress,
221                                            uint64_t FinalAddress,
222                                            uint64_t Value,
223                                            bool isPCRel,
224                                            unsigned Type,
225                                            unsigned Size,
226                                            int64_t Addend) {
227  // If the relocation is PC-relative, the value to be encoded is the
228  // pointer difference.
229  if (isPCRel) {
230    Value -= FinalAddress;
231    // ARM PCRel relocations have an effective-PC offset of two instructions
232    // (four bytes in Thumb mode, 8 bytes in ARM mode).
233    // FIXME: For now, assume ARM mode.
234    Value -= 8;
235  }
236
237  switch(Type) {
238  default:
239    llvm_unreachable("Invalid relocation type!");
240  case macho::RIT_Vanilla: {
241    // Mask in the target value a byte at a time (we don't have an alignment
242    // guarantee for the target address, so this is safest).
243    uint8_t *p = (uint8_t*)LocalAddress;
244    for (unsigned i = 0; i < Size; ++i) {
245      *p++ = (uint8_t)Value;
246      Value >>= 8;
247    }
248    break;
249  }
250  case macho::RIT_ARM_Branch24Bit: {
251    // Mask the value into the target address. We know instructions are
252    // 32-bit aligned, so we can do it all at once.
253    uint32_t *p = (uint32_t*)LocalAddress;
254    // The low two bits of the value are not encoded.
255    Value >>= 2;
256    // Mask the value to 24 bits.
257    Value &= 0xffffff;
258    // FIXME: If the destination is a Thumb function (and the instruction
259    // is a non-predicated BL instruction), we need to change it to a BLX
260    // instruction instead.
261
262    // Insert the value into the instruction.
263    *p = (*p & ~0xffffff) | Value;
264    break;
265  }
266  case macho::RIT_ARM_ThumbBranch22Bit:
267  case macho::RIT_ARM_ThumbBranch32Bit:
268  case macho::RIT_ARM_Half:
269  case macho::RIT_ARM_HalfDifference:
270  case macho::RIT_Pair:
271  case macho::RIT_Difference:
272  case macho::RIT_ARM_LocalDifference:
273  case macho::RIT_ARM_PreboundLazyPointer:
274    return Error("Relocation type not implemented yet!");
275  }
276  return false;
277}
278
279void RuntimeDyldMachO::processRelocationRef(unsigned SectionID,
280                                            RelocationRef RelI,
281                                            ObjectImage &Obj,
282                                            ObjSectionToIDMap &ObjSectionToID,
283                                            const SymbolTableMap &Symbols,
284                                            StubMap &Stubs) {
285  const ObjectFile *OF = Obj.getObjectFile();
286  const MachOObjectFile *MachO = static_cast<const MachOObjectFile*>(OF);
287  macho::RelocationEntry RE = MachO->getRelocation(RelI.getRawDataRefImpl());
288
289  uint32_t RelType = MachO->getAnyRelocationType(RE);
290  RelocationValueRef Value;
291  SectionEntry &Section = Sections[SectionID];
292
293  bool isExtern = MachO->getPlainRelocationExternal(RE);
294  bool IsPCRel = MachO->getAnyRelocationPCRel(RE);
295  unsigned Size = MachO->getAnyRelocationLength(RE);
296  uint64_t Offset;
297  RelI.getOffset(Offset);
298  uint8_t *LocalAddress = Section.Address + Offset;
299  unsigned NumBytes = 1 << Size;
300  uint64_t Addend = 0;
301  memcpy(&Addend, LocalAddress, NumBytes);
302
303  if (isExtern) {
304    // Obtain the symbol name which is referenced in the relocation
305    SymbolRef Symbol;
306    RelI.getSymbol(Symbol);
307    StringRef TargetName;
308    Symbol.getName(TargetName);
309    // First search for the symbol in the local symbol table
310    SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data());
311    if (lsi != Symbols.end()) {
312      Value.SectionID = lsi->second.first;
313      Value.Addend = lsi->second.second + Addend;
314    } else {
315      // Search for the symbol in the global symbol table
316      SymbolTableMap::const_iterator gsi = GlobalSymbolTable.find(TargetName.data());
317      if (gsi != GlobalSymbolTable.end()) {
318        Value.SectionID = gsi->second.first;
319        Value.Addend = gsi->second.second + Addend;
320      } else {
321        Value.SymbolName = TargetName.data();
322        Value.Addend = Addend;
323      }
324    }
325  } else {
326    SectionRef Sec = MachO->getRelocationSection(RE);
327    Value.SectionID = findOrEmitSection(Obj, Sec, true, ObjSectionToID);
328    uint64_t Addr;
329    Sec.getAddress(Addr);
330    Value.Addend = Addend - Addr;
331  }
332
333  if (Arch == Triple::x86_64 && RelType == macho::RIT_X86_64_GOT) {
334    assert(IsPCRel);
335    assert(Size == 2);
336    StubMap::const_iterator i = Stubs.find(Value);
337    uint8_t *Addr;
338    if (i != Stubs.end()) {
339      Addr = Section.Address + i->second;
340    } else {
341      Stubs[Value] = Section.StubOffset;
342      uint8_t *GOTEntry = Section.Address + Section.StubOffset;
343      RelocationEntry RE(SectionID, Section.StubOffset,
344                         macho::RIT_X86_64_Unsigned, Value.Addend - 4, false,
345                         3);
346      if (Value.SymbolName)
347        addRelocationForSymbol(RE, Value.SymbolName);
348      else
349        addRelocationForSection(RE, Value.SectionID);
350      Section.StubOffset += 8;
351      Addr = GOTEntry;
352    }
353    resolveRelocation(Section, Offset, (uint64_t)Addr,
354                      macho::RIT_X86_64_Unsigned, 4, true, 2);
355  } else if (Arch == Triple::arm &&
356             (RelType & 0xf) == macho::RIT_ARM_Branch24Bit) {
357    // This is an ARM branch relocation, need to use a stub function.
358
359    //  Look up for existing stub.
360    StubMap::const_iterator i = Stubs.find(Value);
361    if (i != Stubs.end())
362      resolveRelocation(Section, Offset,
363                        (uint64_t)Section.Address + i->second,
364                        RelType, 0, IsPCRel, Size);
365    else {
366      // Create a new stub function.
367      Stubs[Value] = Section.StubOffset;
368      uint8_t *StubTargetAddr = createStubFunction(Section.Address +
369                                                   Section.StubOffset);
370      RelocationEntry RE(SectionID, StubTargetAddr - Section.Address,
371                         macho::RIT_Vanilla, Value.Addend);
372      if (Value.SymbolName)
373        addRelocationForSymbol(RE, Value.SymbolName);
374      else
375        addRelocationForSection(RE, Value.SectionID);
376      resolveRelocation(Section, Offset,
377                        (uint64_t)Section.Address + Section.StubOffset,
378                        RelType, 0, IsPCRel, Size);
379      Section.StubOffset += getMaxStubSize();
380    }
381  } else {
382    RelocationEntry RE(SectionID, Offset, RelType, Value.Addend,
383                       IsPCRel, Size);
384    if (Value.SymbolName)
385      addRelocationForSymbol(RE, Value.SymbolName);
386    else
387      addRelocationForSection(RE, Value.SectionID);
388  }
389}
390
391
392bool RuntimeDyldMachO::isCompatibleFormat(
393        const ObjectBuffer *InputBuffer) const {
394  if (InputBuffer->getBufferSize() < 4)
395    return false;
396  StringRef Magic(InputBuffer->getBufferStart(), 4);
397  if (Magic == "\xFE\xED\xFA\xCE") return true;
398  if (Magic == "\xCE\xFA\xED\xFE") return true;
399  if (Magic == "\xFE\xED\xFA\xCF") return true;
400  if (Magic == "\xCF\xFA\xED\xFE") return true;
401  return false;
402}
403
404} // end namespace llvm
405