LLVM  12.0.0git
RuntimeDyldCOFFAArch64.h
Go to the documentation of this file.
1 //===-- RuntimeDyldCOFFAArch64.h --- COFF/AArch64 specific code ---*- C++
2 //-*-===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // COFF AArch64 support for MC-JIT runtime dynamic linker.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFAARCH64_H
15 #define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFAARCH64_H
16 
17 #include "../RuntimeDyldCOFF.h"
18 #include "llvm/BinaryFormat/COFF.h"
19 #include "llvm/Object/COFF.h"
20 #include "llvm/Support/Endian.h"
21 
22 #define DEBUG_TYPE "dyld"
23 
24 using namespace llvm::support::endian;
25 
26 namespace llvm {
27 
28 // This relocation type is used for handling long branch instruction
29 // throught the Stub.
30 enum InternalRelocationType : unsigned {
32 };
33 
34 static void add16(uint8_t *p, int16_t v) { write16le(p, read16le(p) + v); }
35 static void or32le(void *P, int32_t V) { write32le(P, read32le(P) | V); }
36 
37 static void write32AArch64Imm(uint8_t *T, uint64_t imm, uint32_t rangeLimit) {
38  uint32_t orig = read32le(T);
39  orig &= ~(0xFFF << 10);
40  write32le(T, orig | ((imm & (0xFFF >> rangeLimit)) << 10));
41 }
42 
43 static void write32AArch64Ldr(uint8_t *T, uint64_t imm) {
44  uint32_t orig = read32le(T);
45  uint32_t size = orig >> 30;
46  // 0x04000000 indicates SIMD/FP registers
47  // 0x00800000 indicates 128 bit
48  if ((orig & 0x04800000) == 0x04800000)
49  size += 4;
50  if ((imm & ((1 << size) - 1)) != 0)
51  assert(0 && "misaligned ldr/str offset");
52  write32AArch64Imm(T, imm >> size, size);
53 }
54 
55 static void write32AArch64Addr(void *T, uint64_t s, uint64_t p, int shift) {
56  uint64_t Imm = (s >> shift) - (p >> shift);
57  uint32_t ImmLo = (Imm & 0x3) << 29;
58  uint32_t ImmHi = (Imm & 0x1FFFFC) << 3;
59  uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3);
60  write32le(T, (read32le(T) & ~Mask) | ImmLo | ImmHi);
61 }
62 
64 
65 private:
66  // When a module is loaded we save the SectionID of the unwind
67  // sections in a table until we receive a request to register all
68  // unregisteredEH frame sections with the memory manager.
69  SmallVector<SID, 2> UnregisteredEHFrameSections;
70  SmallVector<SID, 2> RegisteredEHFrameSections;
71  uint64_t ImageBase;
72 
73  // Fake an __ImageBase pointer by returning the section with the lowest adress
74  uint64_t getImageBase() {
75  if (!ImageBase) {
77  for (const SectionEntry &Section : Sections)
78  // The Sections list may contain sections that weren't loaded for
79  // whatever reason: they may be debug sections, and ProcessAllSections
80  // is false, or they may be sections that contain 0 bytes. If the
81  // section isn't loaded, the load address will be 0, and it should not
82  // be included in the ImageBase calculation.
83  if (Section.getLoadAddress() != 0)
84  ImageBase = std::min(ImageBase, Section.getLoadAddress());
85  }
86  return ImageBase;
87  }
88 
89 public:
92  : RuntimeDyldCOFF(MM, Resolver, 8, COFF::IMAGE_REL_ARM64_ADDR64),
93  ImageBase(0) {}
94 
95  unsigned getStubAlignment() override { return 8; }
96 
97  unsigned getMaxStubSize() const override { return 20; }
98 
99  std::tuple<uint64_t, uint64_t, uint64_t>
100  generateRelocationStub(unsigned SectionID, StringRef TargetName,
101  uint64_t Offset, uint64_t RelType, uint64_t Addend,
102  StubMap &Stubs) {
103  uintptr_t StubOffset;
104  SectionEntry &Section = Sections[SectionID];
105 
106  RelocationValueRef OriginalRelValueRef;
107  OriginalRelValueRef.SectionID = SectionID;
108  OriginalRelValueRef.Offset = Offset;
109  OriginalRelValueRef.Addend = Addend;
110  OriginalRelValueRef.SymbolName = TargetName.data();
111 
112  auto Stub = Stubs.find(OriginalRelValueRef);
113  if (Stub == Stubs.end()) {
114  LLVM_DEBUG(dbgs() << " Create a new stub function for "
115  << TargetName.data() << "\n");
116 
117  StubOffset = Section.getStubOffset();
118  Stubs[OriginalRelValueRef] = StubOffset;
119  createStubFunction(Section.getAddressWithOffset(StubOffset));
120  Section.advanceStubOffset(getMaxStubSize());
121  } else {
122  LLVM_DEBUG(dbgs() << " Stub function found for " << TargetName.data()
123  << "\n");
124  StubOffset = Stub->second;
125  }
126 
127  // Resolve original relocation to stub function.
128  const RelocationEntry RE(SectionID, Offset, RelType, Addend);
129  resolveRelocation(RE, Section.getLoadAddressWithOffset(StubOffset));
130 
131  // adjust relocation info so resolution writes to the stub function
132  // Here an internal relocation type is used for resolving long branch via
133  // stub instruction.
134  Addend = 0;
135  Offset = StubOffset;
137 
138  return std::make_tuple(Offset, RelType, Addend);
139  }
140 
143  const object::ObjectFile &Obj,
144  ObjSectionToIDMap &ObjSectionToID,
145  StubMap &Stubs) override {
146 
147  auto Symbol = RelI->getSymbol();
148  if (Symbol == Obj.symbol_end())
149  report_fatal_error("Unknown symbol in relocation");
150 
151  Expected<StringRef> TargetNameOrErr = Symbol->getName();
152  if (!TargetNameOrErr)
153  return TargetNameOrErr.takeError();
154  StringRef TargetName = *TargetNameOrErr;
155 
156  auto SectionOrErr = Symbol->getSection();
157  if (!SectionOrErr)
158  return SectionOrErr.takeError();
159  auto Section = *SectionOrErr;
160 
161  uint64_t RelType = RelI->getType();
162  uint64_t Offset = RelI->getOffset();
163 
164  // If there is no section, this must be an external reference.
165  bool IsExtern = Section == Obj.section_end();
166 
167  // Determine the Addend used to adjust the relocation value.
168  uint64_t Addend = 0;
169  SectionEntry &AddendSection = Sections[SectionID];
170  uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset;
171  uint8_t *Displacement = (uint8_t *)ObjTarget;
172 
173  unsigned TargetSectionID = -1;
174  uint64_t TargetOffset = -1;
175 
176  if (TargetName.startswith(getImportSymbolPrefix())) {
177  TargetSectionID = SectionID;
178  TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName);
179  TargetName = StringRef();
180  IsExtern = false;
181  } else if (!IsExtern) {
182  if (auto TargetSectionIDOrErr = findOrEmitSection(
183  Obj, *Section, Section->isText(), ObjSectionToID))
184  TargetSectionID = *TargetSectionIDOrErr;
185  else
186  return TargetSectionIDOrErr.takeError();
187 
188  TargetOffset = getSymbolOffset(*Symbol);
189  }
190 
191  switch (RelType) {
196  Addend = read32le(Displacement);
197  break;
199  uint32_t orig = read32le(Displacement);
200  Addend = (orig & 0x03FFFFFF) << 2;
201 
202  if (IsExtern)
203  std::tie(Offset, RelType, Addend) = generateRelocationStub(
204  SectionID, TargetName, Offset, RelType, Addend, Stubs);
205  break;
206  }
208  uint32_t orig = read32le(Displacement);
209  Addend = (orig & 0x00FFFFE0) >> 3;
210  break;
211  }
213  uint32_t orig = read32le(Displacement);
214  Addend = (orig & 0x000FFFE0) >> 3;
215  break;
216  }
219  uint32_t orig = read32le(Displacement);
220  Addend = ((orig >> 29) & 0x3) | ((orig >> 3) & 0x1FFFFC);
221  break;
222  }
225  uint32_t orig = read32le(Displacement);
226  Addend = ((orig >> 10) & 0xFFF);
227  break;
228  }
230  Addend = read64le(Displacement);
231  break;
232  }
233  default:
234  break;
235  }
236 
237 #if !defined(NDEBUG)
238  SmallString<32> RelTypeName;
239  RelI->getTypeName(RelTypeName);
240 
241  LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
242  << " RelType: " << RelTypeName << " TargetName: "
243  << TargetName << " Addend " << Addend << "\n");
244 #endif
245 
246  if (IsExtern) {
247  RelocationEntry RE(SectionID, Offset, RelType, Addend);
248  addRelocationForSymbol(RE, TargetName);
249  } else {
250  RelocationEntry RE(SectionID, Offset, RelType, TargetOffset + Addend);
251  addRelocationForSection(RE, TargetSectionID);
252  }
253  return ++RelI;
254  }
255 
256  void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
257  const auto Section = Sections[RE.SectionID];
258  uint8_t *Target = Section.getAddressWithOffset(RE.Offset);
259  uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
260 
261  switch (RE.RelType) {
262  default:
263  llvm_unreachable("unsupported relocation type");
265  // This relocation is ignored.
266  break;
267  }
269  // The page base of the target, for ADRP instruction.
270  Value += RE.Addend;
271  write32AArch64Addr(Target, Value, FinalAddress, 12);
272  break;
273  }
275  // The 12-bit relative displacement to the target, for instruction ADR
276  Value += RE.Addend;
277  write32AArch64Addr(Target, Value, FinalAddress, 0);
278  break;
279  }
281  // The 12-bit page offset of the target,
282  // for instructions ADD/ADDS (immediate) with zero shift.
283  Value += RE.Addend;
284  write32AArch64Imm(Target, Value & 0xFFF, 0);
285  break;
286  }
288  // The 12-bit page offset of the target,
289  // for instruction LDR (indexed, unsigned immediate).
290  Value += RE.Addend;
291  write32AArch64Ldr(Target, Value & 0xFFF);
292  break;
293  }
295  // The 32-bit VA of the target.
296  uint32_t VA = Value + RE.Addend;
297  write32le(Target, VA);
298  break;
299  }
301  // The target's 32-bit RVA.
302  uint64_t RVA = Value + RE.Addend - getImageBase();
303  write32le(Target, RVA);
304  break;
305  }
307  // Encode the immadiate value for generated Stub instruction (MOVZ)
308  or32le(Target + 12, ((Value + RE.Addend) & 0xFFFF) << 5);
309  or32le(Target + 8, ((Value + RE.Addend) & 0xFFFF0000) >> 11);
310  or32le(Target + 4, ((Value + RE.Addend) & 0xFFFF00000000) >> 27);
311  or32le(Target + 0, ((Value + RE.Addend) & 0xFFFF000000000000) >> 43);
312  break;
313  }
315  // The 26-bit relative displacement to the target, for B and BL
316  // instructions.
317  uint64_t PCRelVal = Value + RE.Addend - FinalAddress;
318  assert(isInt<28>(PCRelVal) && "Branch target is out of range.");
319  write32le(Target, (read32le(Target) & ~(0x03FFFFFF)) |
320  (PCRelVal & 0x0FFFFFFC) >> 2);
321  break;
322  }
324  // The 19-bit offset to the relocation target,
325  // for conditional B instruction.
326  uint64_t PCRelVal = Value + RE.Addend - FinalAddress;
327  assert(isInt<21>(PCRelVal) && "Branch target is out of range.");
328  write32le(Target, (read32le(Target) & ~(0x00FFFFE0)) |
329  (PCRelVal & 0x001FFFFC) << 3);
330  break;
331  }
333  // The 14-bit offset to the relocation target,
334  // for instructions TBZ and TBNZ.
335  uint64_t PCRelVal = Value + RE.Addend - FinalAddress;
336  assert(isInt<16>(PCRelVal) && "Branch target is out of range.");
337  write32le(Target, (read32le(Target) & ~(0x000FFFE0)) |
338  (PCRelVal & 0x0000FFFC) << 3);
339  break;
340  }
342  // The 64-bit VA of the relocation target.
343  write64le(Target, Value + RE.Addend);
344  break;
345  }
347  // 16-bit section index of the section that contains the target.
348  assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX &&
349  "relocation overflow");
350  add16(Target, RE.SectionID);
351  break;
352  }
354  // 32-bit offset of the target from the beginning of its section.
355  assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&
356  "Relocation overflow");
357  assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&
358  "Relocation underflow");
359  write32le(Target, RE.Addend);
360  break;
361  }
363  // The 32-bit relative address from the byte following the relocation.
364  uint64_t Result = Value - FinalAddress - 4;
365  write32le(Target, Result + RE.Addend);
366  break;
367  }
368  }
369  }
370 
371  void registerEHFrames() override {}
372 };
373 
374 } // End namespace llvm
375 
376 #endif
RelocationEntry - used to represent relocations internally in the dynamic linker. ...
static void add16(uint8_t *p, int16_t v)
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:140
This class represents lattice values for constants.
Definition: AllocatorList.h:23
LLVM_NODISCARD bool startswith(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition: StringRef.h:289
uint64_t getLoadAddressWithOffset(unsigned OffsetBytes) const
Return the load address of this section with an offset.
This class is the base class for all object file types.
Definition: ObjectFile.h:225
void write32le(void *P, uint32_t V)
Definition: Endian.h:416
constexpr bool isInt< 16 >(int64_t x)
Definition: MathExtras.h:371
uint16_t read16le(const void *P)
Definition: Endian.h:380
Error takeError()
Take ownership of the stored error.
Definition: Error.h:557
unsigned SectionID
SectionID - the section this relocation points to.
void write16le(void *P, uint16_t V)
Definition: Endian.h:415
std::map< RelocationValueRef, uintptr_t > StubMap
Tagged union holding either a T or a Error.
Definition: APFloat.h:42
std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E&#39;s largest value.
Definition: BitmaskEnum.h:80
static void or32le(void *P, int32_t V)
#define P(N)
std::tuple< uint64_t, uint64_t, uint64_t > generateRelocationStub(unsigned SectionID, StringRef TargetName, uint64_t Offset, uint64_t RelType, uint64_t Addend, StubMap &Stubs)
Interface for looking up the initializer for a variable name, used by Init::resolveReferences.
Definition: Record.h:1968
Expected< ExpressionValue > min(const ExpressionValue &Lhs, const ExpressionValue &Rhs)
Definition: FileCheck.cpp:339
Symbol resolution interface.
Definition: JITSymbol.h:371
virtual basic_symbol_iterator symbol_end() const =0
uintptr_t getObjAddress() const
static void write32AArch64Imm(uint8_t *T, uint64_t imm, uint32_t rangeLimit)
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Align max(MaybeAlign Lhs, Align Rhs)
Definition: Alignment.h:350
int64_t Addend
Addend - the relocation addend encoded in the instruction itself.
uint32_t RelType
RelType - relocation type.
Expected< object::relocation_iterator > processRelocationRef(unsigned SectionID, object::relocation_iterator RelI, const object::ObjectFile &Obj, ObjSectionToIDMap &ObjSectionToID, StubMap &Stubs) override
Parses one or more object file relocations (some object files use relocation pairs) and stores it to ...
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:132
Target - Wrapper for Target specific information.
uintptr_t getStubOffset() const
static void write32AArch64Ldr(uint8_t *T, uint64_t imm)
uint64_t Offset
Offset - offset into the section.
uint64_t read64le(const void *P)
Definition: Endian.h:382
void write64le(void *P, uint64_t V)
Definition: Endian.h:417
virtual section_iterator section_end() const =0
std::map< SectionRef, unsigned > ObjSectionToIDMap
uint8_t * getAddressWithOffset(unsigned OffsetBytes) const
Return the address of this section with an offset.
static void write32AArch64Addr(void *T, uint64_t s, uint64_t p, int shift)
uint32_t read32le(const void *P)
Definition: Endian.h:381
SectionEntry - represents a section emitted into memory by the dynamic linker.
LLVM_NODISCARD const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:152
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition: STLExtras.h:1479
void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override
A object file specific relocation resolver.
RuntimeDyldCOFFAArch64(RuntimeDyld::MemoryManager &MM, JITSymbolResolver &Resolver)
LLVM Value Representation.
Definition: Value.h:75
void advanceStubOffset(unsigned StubSize)
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:57
uint64_t resolveRelocation(RelocationResolver Resolver, const RelocationRef &R, uint64_t S, uint64_t LocData)
#define LLVM_DEBUG(X)
Definition: Debug.h:122
unsigned getMaxStubSize() const override