LLVM  4.0.0
RuntimeDyldMachOARM.h
Go to the documentation of this file.
1 //===----- RuntimeDyldMachOARM.h ---- MachO/ARM specific code. ----*- 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 #ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H
11 #define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H
12 
13 #include "../RuntimeDyldMachO.h"
14 #include <string>
15 
16 #define DEBUG_TYPE "dyld"
17 
18 namespace llvm {
19 
21  : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> {
22 private:
24 
25 public:
26 
28 
31  : RuntimeDyldMachOCRTPBase(MM, Resolver) {}
32 
33  unsigned getMaxStubSize() override { return 8; }
34 
35  unsigned getStubAlignment() override { return 4; }
36 
37  int64_t decodeAddend(const RelocationEntry &RE) const {
39  uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
40 
41  switch (RE.RelType) {
42  default:
43  return memcpyAddend(RE);
44  case MachO::ARM_RELOC_BR24: {
45  uint32_t Temp = readBytesUnaligned(LocalAddress, 4);
46  Temp &= 0x00ffffff; // Mask out the opcode.
47  // Now we've got the shifted immediate, shift by 2, sign extend and ret.
48  return SignExtend32<26>(Temp << 2);
49  }
50  }
51  }
52 
54  processRelocationRef(unsigned SectionID, relocation_iterator RelI,
55  const ObjectFile &BaseObjT,
56  ObjSectionToIDMap &ObjSectionToID,
57  StubMap &Stubs) override {
58  const MachOObjectFile &Obj =
59  static_cast<const MachOObjectFile &>(BaseObjT);
61  Obj.getRelocation(RelI->getRawDataRefImpl());
62  uint32_t RelType = Obj.getAnyRelocationType(RelInfo);
63 
64  if (Obj.isRelocationScattered(RelInfo)) {
65  if (RelType == MachO::ARM_RELOC_HALF_SECTDIFF)
66  return processHALFSECTDIFFRelocation(SectionID, RelI, Obj,
67  ObjSectionToID);
68  else if (RelType == MachO::GENERIC_RELOC_VANILLA)
69  return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID);
70  else
71  return ++RelI;
72  }
73 
74  // Sanity check relocation type.
75  switch (RelType) {
83  default:
84  if (RelType > MachO::ARM_RELOC_HALF_SECTDIFF)
85  return make_error<RuntimeDyldError>(("MachO ARM relocation type " +
86  Twine(RelType) +
87  " is out of range").str());
88  break;
89  }
90 
91  RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI));
92  RE.Addend = decodeAddend(RE);
94  if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID))
95  Value = *ValueOrErr;
96  else
97  return ValueOrErr.takeError();
98 
99  if (RE.IsPCRel)
100  makeValueAddendPCRel(Value, RelI, 8);
101 
102  if ((RE.RelType & 0xf) == MachO::ARM_RELOC_BR24)
103  processBranchRelocation(RE, Value, Stubs);
104  else {
105  RE.Addend = Value.Offset;
106  if (Value.SymbolName)
108  else
110  }
111 
112  return ++RelI;
113  }
114 
115  void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
116  DEBUG(dumpRelocationToResolve(RE, Value));
117  const SectionEntry &Section = Sections[RE.SectionID];
118  uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
119 
120  // If the relocation is PC-relative, the value to be encoded is the
121  // pointer difference.
122  if (RE.IsPCRel) {
123  uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
124  Value -= FinalAddress;
125  // ARM PCRel relocations have an effective-PC offset of two instructions
126  // (four bytes in Thumb mode, 8 bytes in ARM mode).
127  // FIXME: For now, assume ARM mode.
128  Value -= 8;
129  }
130 
131  switch (RE.RelType) {
133  writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size);
134  break;
135  case MachO::ARM_RELOC_BR24: {
136  // Mask the value into the target address. We know instructions are
137  // 32-bit aligned, so we can do it all at once.
138  Value += RE.Addend;
139  // The low two bits of the value are not encoded.
140  Value >>= 2;
141  // Mask the value to 24 bits.
142  uint64_t FinalValue = Value & 0xffffff;
143  // FIXME: If the destination is a Thumb function (and the instruction
144  // is a non-predicated BL instruction), we need to change it to a BLX
145  // instruction instead.
146 
147  // Insert the value into the instruction.
148  uint32_t Temp = readBytesUnaligned(LocalAddress, 4);
149  writeBytesUnaligned((Temp & ~0xffffff) | FinalValue, LocalAddress, 4);
150 
151  break;
152  }
154  uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress();
155  uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress();
156  assert((Value == SectionABase || Value == SectionBBase) &&
157  "Unexpected HALFSECTDIFF relocation value.");
158  Value = SectionABase - SectionBBase + RE.Addend;
159  if (RE.Size & 0x1) // :upper16:
160  Value = (Value >> 16);
161  Value &= 0xffff;
162 
163  uint32_t Insn = readBytesUnaligned(LocalAddress, 4);
164  Insn = (Insn & 0xfff0f000) | ((Value & 0xf000) << 4) | (Value & 0x0fff);
165  writeBytesUnaligned(Insn, LocalAddress, 4);
166  break;
167  }
168 
169  default:
170  llvm_unreachable("Invalid relocation type");
171  }
172  }
173 
174  Error finalizeSection(const ObjectFile &Obj, unsigned SectionID,
175  const SectionRef &Section) {
176  StringRef Name;
177  Section.getName(Name);
178 
179  if (Name == "__nl_symbol_ptr")
180  return populateIndirectSymbolPointersSection(cast<MachOObjectFile>(Obj),
181  Section, SectionID);
182  return Error::success();
183  }
184 
185 private:
186 
187  void processBranchRelocation(const RelocationEntry &RE,
188  const RelocationValueRef &Value,
189  StubMap &Stubs) {
190  // This is an ARM branch relocation, need to use a stub function.
191  // Look up for existing stub.
193  RuntimeDyldMachO::StubMap::const_iterator i = Stubs.find(Value);
194  uint8_t *Addr;
195  if (i != Stubs.end()) {
196  Addr = Section.getAddressWithOffset(i->second);
197  } else {
198  // Create a new stub function.
199  Stubs[Value] = Section.getStubOffset();
200  uint8_t *StubTargetAddr = createStubFunction(
201  Section.getAddressWithOffset(Section.getStubOffset()));
202  RelocationEntry StubRE(
203  RE.SectionID, StubTargetAddr - Section.getAddress(),
204  MachO::GENERIC_RELOC_VANILLA, Value.Offset, false, 2);
205  if (Value.SymbolName)
206  addRelocationForSymbol(StubRE, Value.SymbolName);
207  else
208  addRelocationForSection(StubRE, Value.SectionID);
209  Addr = Section.getAddressWithOffset(Section.getStubOffset());
211  }
212  RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, 0,
213  RE.IsPCRel, RE.Size);
214  resolveRelocation(TargetRE, (uint64_t)Addr);
215  }
216 
218  processHALFSECTDIFFRelocation(unsigned SectionID, relocation_iterator RelI,
219  const ObjectFile &BaseTObj,
220  ObjSectionToIDMap &ObjSectionToID) {
221  const MachOObjectFile &MachO =
222  static_cast<const MachOObjectFile&>(BaseTObj);
224  MachO.getRelocation(RelI->getRawDataRefImpl());
225 
226 
227  // For a half-diff relocation the length bits actually record whether this
228  // is a movw/movt, and whether this is arm or thumb.
229  // Bit 0 indicates movw (b0 == 0) or movt (b0 == 1).
230  // Bit 1 indicates arm (b1 == 0) or thumb (b1 == 1).
231  unsigned HalfDiffKindBits = MachO.getAnyRelocationLength(RE);
232  if (HalfDiffKindBits & 0x2)
233  llvm_unreachable("Thumb not yet supported.");
234 
235  SectionEntry &Section = Sections[SectionID];
236  uint32_t RelocType = MachO.getAnyRelocationType(RE);
237  bool IsPCRel = MachO.getAnyRelocationPCRel(RE);
238  uint64_t Offset = RelI->getOffset();
239  uint8_t *LocalAddress = Section.getAddressWithOffset(Offset);
240  int64_t Immediate = readBytesUnaligned(LocalAddress, 4); // Copy the whole instruction out.
241  Immediate = ((Immediate >> 4) & 0xf000) | (Immediate & 0xfff);
242 
243  ++RelI;
245  MachO.getRelocation(RelI->getRawDataRefImpl());
246  uint32_t AddrA = MachO.getScatteredRelocationValue(RE);
247  section_iterator SAI = getSectionByAddress(MachO, AddrA);
248  assert(SAI != MachO.section_end() && "Can't find section for address A");
249  uint64_t SectionABase = SAI->getAddress();
250  uint64_t SectionAOffset = AddrA - SectionABase;
251  SectionRef SectionA = *SAI;
252  bool IsCode = SectionA.isText();
253  uint32_t SectionAID = ~0U;
254  if (auto SectionAIDOrErr =
255  findOrEmitSection(MachO, SectionA, IsCode, ObjSectionToID))
256  SectionAID = *SectionAIDOrErr;
257  else
258  return SectionAIDOrErr.takeError();
259 
260  uint32_t AddrB = MachO.getScatteredRelocationValue(RE2);
261  section_iterator SBI = getSectionByAddress(MachO, AddrB);
262  assert(SBI != MachO.section_end() && "Can't find section for address B");
263  uint64_t SectionBBase = SBI->getAddress();
264  uint64_t SectionBOffset = AddrB - SectionBBase;
265  SectionRef SectionB = *SBI;
266  uint32_t SectionBID = ~0U;
267  if (auto SectionBIDOrErr =
268  findOrEmitSection(MachO, SectionB, IsCode, ObjSectionToID))
269  SectionBID = *SectionBIDOrErr;
270  else
271  return SectionBIDOrErr.takeError();
272 
273  uint32_t OtherHalf = MachO.getAnyRelocationAddress(RE2) & 0xffff;
274  unsigned Shift = (HalfDiffKindBits & 0x1) ? 16 : 0;
275  uint32_t FullImmVal = (Immediate << Shift) | (OtherHalf << (16 - Shift));
276  int64_t Addend = FullImmVal - (AddrA - AddrB);
277 
278  // addend = Encoded - Expected
279  // = Encoded - (AddrA - AddrB)
280 
281  DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA << ", AddrB: " << AddrB
282  << ", Addend: " << Addend << ", SectionA ID: " << SectionAID
283  << ", SectionAOffset: " << SectionAOffset
284  << ", SectionB ID: " << SectionBID
285  << ", SectionBOffset: " << SectionBOffset << "\n");
286  RelocationEntry R(SectionID, Offset, RelocType, Addend, SectionAID,
287  SectionAOffset, SectionBID, SectionBOffset, IsPCRel,
288  HalfDiffKindBits);
289 
290  addRelocationForSection(R, SectionAID);
291  addRelocationForSection(R, SectionBID);
292 
293  return ++RelI;
294  }
295 
296 };
297 }
298 
299 #undef DEBUG_TYPE
300 
301 #endif
unsigned getStubAlignment() override
RelocationEntry - used to represent relocations internally in the dynamic linker. ...
void writeBytesUnaligned(uint64_t Value, uint8_t *Dst, unsigned Size) const
Endian-aware write.
size_t i
unsigned getAnyRelocationType(const MachO::any_relocation_info &RE) const
uint8_t * getAddress() const
This class is the base class for all object file types.
Definition: ObjectFile.h:178
unsigned getMaxStubSize() override
bool IsPCRel
True if this is a PCRel relocation (MachO specific).
unsigned SectionID
SectionID - the section this relocation points to.
int64_t decodeAddend(const RelocationEntry &RE) const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
Expected< relocation_iterator > processRelocationRef(unsigned SectionID, relocation_iterator RelI, const ObjectFile &BaseObjT, ObjSectionToIDMap &ObjSectionToID, StubMap &Stubs) override
Parses one or more object file relocations (some object files use relocation pairs) and stores it to ...
RelocationEntry getRelocationEntry(unsigned SectionID, const ObjectFile &BaseTObj, const relocation_iterator &RI) const
Given a relocation_iterator for a non-scattered relocation, construct a RelocationEntry and fill in t...
int64_t memcpyAddend(const RelocationEntry &RE) const
This convenience method uses memcpy to extract a contiguous addend (the addend size and offset are ta...
std::map< RelocationValueRef, uintptr_t > StubMap
Tagged union holding either a T or a Error.
uint32_t getScatteredRelocationValue(const MachO::any_relocation_info &RE) const
std::error_code getName(StringRef &Result) const
Definition: ObjectFile.h:372
uint64_t getLoadAddressWithOffset(unsigned OffsetBytes) const
Return the load address of this section with an offset.
RuntimeDyldMachOARM(RuntimeDyld::MemoryManager &MM, JITSymbolResolver &Resolver)
void dumpRelocationToResolve(const RelocationEntry &RE, uint64_t Value) const
Dump information about the relocation entry (RE) and resolved value.
RuntimeDyldMachOTarget - Templated base class for generic MachO linker algorithms and data structures...
Error finalizeSection(const ObjectFile &Obj, unsigned SectionID, const SectionRef &Section)
Expected< RelocationValueRef > getRelocationValueRef(const ObjectFile &BaseTObj, const relocation_iterator &RI, const RelocationEntry &RE, ObjSectionToIDMap &ObjSectionToID)
Construct a RelocationValueRef representing the relocation target.
void addRelocationForSymbol(const RelocationEntry &RE, StringRef SymbolName)
uint8_t * getAddressWithOffset(unsigned OffsetBytes) const
Return the address of this section with an offset.
unsigned getAnyRelocationAddress(const MachO::any_relocation_info &RE) const
MachO::any_relocation_info getRelocation(DataRefImpl Rel) const
void addRelocationForSection(const RelocationEntry &RE, unsigned SectionID)
uint64_t readBytesUnaligned(uint8_t *Src, unsigned Size) const
Endian-aware read Read the least significant Size bytes from Src.
bool isText() const
Definition: ObjectFile.h:396
unsigned getAnyRelocationPCRel(const MachO::any_relocation_info &RE) const
uint32_t Offset
Symbol resolution.
Definition: JITSymbol.h:165
uintptr_t getStubOffset() const
Expected< relocation_iterator > processScatteredVANILLA(unsigned SectionID, relocation_iterator RelI, const ObjectFile &BaseObjT, RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID)
Process a scattered vanilla relocation.
Expected< unsigned > findOrEmitSection(const ObjectFile &Obj, const SectionRef &Section, bool IsCode, ObjSectionToIDMap &LocalSections)
Find Section in LocalSections.
static section_iterator getSectionByAddress(const MachOObjectFile &Obj, uint64_t Addr)
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static ErrorSuccess success()
Create a success value.
unsigned getAnyRelocationLength(const MachO::any_relocation_info &RE) const
int64_t Addend
Addend - the relocation addend encoded in the instruction itself.
uint32_t RelType
RelType - relocation type.
JITSymbolResolver & Resolver
uint8_t * createStubFunction(uint8_t *Addr, unsigned AbiVariant=0)
Emits long jump instruction to Addr.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:132
uint64_t Offset
Offset - offset into the section.
std::map< SectionRef, unsigned > ObjSectionToIDMap
SectionEntry - represents a section emitted into memory by the dynamic linker.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
LLVM Value Representation.
Definition: Value.h:71
void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override
A object file specific relocation resolver.
Lightweight error class with error context and mandatory checking.
unsigned Size
The size of this relocation (MachO specific).
section_iterator section_end() const override
#define UNIMPLEMENTED_RELOC(RelType)
#define DEBUG(X)
Definition: Debug.h:100
Error populateIndirectSymbolPointersSection(const MachOObjectFile &Obj, const SectionRef &PTSection, unsigned PTSectionID)
void advanceStubOffset(unsigned StubSize)
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:47
void makeValueAddendPCRel(RelocationValueRef &Value, const relocation_iterator &RI, unsigned OffsetToNextPC)
Make the RelocationValueRef addend PC-relative.
bool isRelocationScattered(const MachO::any_relocation_info &RE) const
This is a value type class that represents a single section in the list of sections in the object fil...
Definition: ObjectFile.h:70