1303231Sdim//===------------- OrcABISupport.cpp - ABI specific support code ----------===//
2303231Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6303231Sdim//
7303231Sdim//===----------------------------------------------------------------------===//
8303231Sdim
9303231Sdim#include "llvm/ExecutionEngine/Orc/OrcABISupport.h"
10303231Sdim#include "llvm/Support/Process.h"
11303231Sdim
12303231Sdimnamespace llvm {
13303231Sdimnamespace orc {
14303231Sdim
15303231Sdimvoid OrcAArch64::writeResolverCode(uint8_t *ResolverMem, JITReentryFn ReentryFn,
16303231Sdim                                   void *CallbackMgr) {
17303231Sdim
18303231Sdim  const uint32_t ResolverCode[] = {
19303231Sdim    // resolver_entry:
20303231Sdim    0xa9bf47fd,        // 0x000:  stp  x29, x17, [sp, #-16]!
21303231Sdim    0x910003fd,        // 0x004:  mov  x29, sp
22303231Sdim    0xa9bf73fb,        // 0x008:  stp  x27, x28, [sp, #-16]!
23303231Sdim    0xa9bf6bf9,        // 0x00c:  stp  x25, x26, [sp, #-16]!
24303231Sdim    0xa9bf63f7,        // 0x010:  stp  x23, x24, [sp, #-16]!
25303231Sdim    0xa9bf5bf5,        // 0x014:  stp  x21, x22, [sp, #-16]!
26303231Sdim    0xa9bf53f3,        // 0x018:  stp  x19, x20, [sp, #-16]!
27303231Sdim    0xa9bf3fee,        // 0x01c:  stp  x14, x15, [sp, #-16]!
28303231Sdim    0xa9bf37ec,        // 0x020:  stp  x12, x13, [sp, #-16]!
29303231Sdim    0xa9bf2fea,        // 0x024:  stp  x10, x11, [sp, #-16]!
30303231Sdim    0xa9bf27e8,        // 0x028:  stp   x8,  x9, [sp, #-16]!
31303231Sdim    0xa9bf1fe6,        // 0x02c:  stp   x6,  x7, [sp, #-16]!
32303231Sdim    0xa9bf17e4,        // 0x030:  stp   x4,  x5, [sp, #-16]!
33303231Sdim    0xa9bf0fe2,        // 0x034:  stp   x2,  x3, [sp, #-16]!
34303231Sdim    0xa9bf07e0,        // 0x038:  stp   x0,  x1, [sp, #-16]!
35303231Sdim    0xadbf7ffe,        // 0x03c:  stp  q30, q31, [sp, #-32]!
36303231Sdim    0xadbf77fc,        // 0x040:  stp  q28, q29, [sp, #-32]!
37303231Sdim    0xadbf6ffa,        // 0x044:  stp  q26, q27, [sp, #-32]!
38303231Sdim    0xadbf67f8,        // 0x048:  stp  q24, q25, [sp, #-32]!
39303231Sdim    0xadbf5ff6,        // 0x04c:  stp  q22, q23, [sp, #-32]!
40303231Sdim    0xadbf57f4,        // 0x050:  stp  q20, q21, [sp, #-32]!
41303231Sdim    0xadbf4ff2,        // 0x054:  stp  q18, q19, [sp, #-32]!
42303231Sdim    0xadbf47f0,        // 0x058:  stp  q16, q17, [sp, #-32]!
43303231Sdim    0xadbf3fee,        // 0x05c:  stp  q14, q15, [sp, #-32]!
44303231Sdim    0xadbf37ec,        // 0x060:  stp  q12, q13, [sp, #-32]!
45303231Sdim    0xadbf2fea,        // 0x064:  stp  q10, q11, [sp, #-32]!
46303231Sdim    0xadbf27e8,        // 0x068:  stp   q8,  q9, [sp, #-32]!
47303231Sdim    0xadbf1fe6,        // 0x06c:  stp   q6,  q7, [sp, #-32]!
48303231Sdim    0xadbf17e4,        // 0x070:  stp   q4,  q5, [sp, #-32]!
49303231Sdim    0xadbf0fe2,        // 0x074:  stp   q2,  q3, [sp, #-32]!
50303231Sdim    0xadbf07e0,        // 0x078:  stp   q0,  q1, [sp, #-32]!
51303231Sdim    0x580004e0,        // 0x07c:  ldr   x0, Lcallbackmgr
52303231Sdim    0xaa1e03e1,        // 0x080:  mov   x1, x30
53303231Sdim    0xd1003021,        // 0x084:  sub   x1,  x1, #12
54303231Sdim    0x58000442,        // 0x088:  ldr   x2, Lreentry_fn_ptr
55303231Sdim    0xd63f0040,        // 0x08c:  blr   x2
56303231Sdim    0xaa0003f1,        // 0x090:  mov   x17, x0
57303231Sdim    0xacc107e0,        // 0x094:  ldp   q0,  q1, [sp], #32
58303231Sdim    0xacc10fe2,        // 0x098:  ldp   q2,  q3, [sp], #32
59303231Sdim    0xacc117e4,        // 0x09c:  ldp   q4,  q5, [sp], #32
60303231Sdim    0xacc11fe6,        // 0x0a0:  ldp   q6,  q7, [sp], #32
61303231Sdim    0xacc127e8,        // 0x0a4:  ldp   q8,  q9, [sp], #32
62303231Sdim    0xacc12fea,        // 0x0a8:  ldp  q10, q11, [sp], #32
63303231Sdim    0xacc137ec,        // 0x0ac:  ldp  q12, q13, [sp], #32
64303231Sdim    0xacc13fee,        // 0x0b0:  ldp  q14, q15, [sp], #32
65303231Sdim    0xacc147f0,        // 0x0b4:  ldp  q16, q17, [sp], #32
66303231Sdim    0xacc14ff2,        // 0x0b8:  ldp  q18, q19, [sp], #32
67303231Sdim    0xacc157f4,        // 0x0bc:  ldp  q20, q21, [sp], #32
68303231Sdim    0xacc15ff6,        // 0x0c0:  ldp  q22, q23, [sp], #32
69303231Sdim    0xacc167f8,        // 0x0c4:  ldp  q24, q25, [sp], #32
70303231Sdim    0xacc16ffa,        // 0x0c8:  ldp  q26, q27, [sp], #32
71303231Sdim    0xacc177fc,        // 0x0cc:  ldp  q28, q29, [sp], #32
72303231Sdim    0xacc17ffe,        // 0x0d0:  ldp  q30, q31, [sp], #32
73303231Sdim    0xa8c107e0,        // 0x0d4:  ldp   x0,  x1, [sp], #16
74303231Sdim    0xa8c10fe2,        // 0x0d8:  ldp   x2,  x3, [sp], #16
75303231Sdim    0xa8c117e4,        // 0x0dc:  ldp   x4,  x5, [sp], #16
76303231Sdim    0xa8c11fe6,        // 0x0e0:  ldp   x6,  x7, [sp], #16
77303231Sdim    0xa8c127e8,        // 0x0e4:  ldp   x8,  x9, [sp], #16
78303231Sdim    0xa8c12fea,        // 0x0e8:  ldp  x10, x11, [sp], #16
79303231Sdim    0xa8c137ec,        // 0x0ec:  ldp  x12, x13, [sp], #16
80303231Sdim    0xa8c13fee,        // 0x0f0:  ldp  x14, x15, [sp], #16
81303231Sdim    0xa8c153f3,        // 0x0f4:  ldp  x19, x20, [sp], #16
82303231Sdim    0xa8c15bf5,        // 0x0f8:  ldp  x21, x22, [sp], #16
83303231Sdim    0xa8c163f7,        // 0x0fc:  ldp  x23, x24, [sp], #16
84303231Sdim    0xa8c16bf9,        // 0x100:  ldp  x25, x26, [sp], #16
85303231Sdim    0xa8c173fb,        // 0x104:  ldp  x27, x28, [sp], #16
86303231Sdim    0xa8c17bfd,        // 0x108:  ldp  x29, x30, [sp], #16
87303231Sdim    0xd65f0220,        // 0x10c:  ret  x17
88303231Sdim    0x01234567,        // 0x110:  Lreentry_fn_ptr:
89303231Sdim    0xdeadbeef,        // 0x114:      .quad 0
90303231Sdim    0x98765432,        // 0x118:  Lcallbackmgr:
91303231Sdim    0xcafef00d         // 0x11c:      .quad 0
92303231Sdim  };
93303231Sdim
94303231Sdim  const unsigned ReentryFnAddrOffset = 0x110;
95303231Sdim  const unsigned CallbackMgrAddrOffset = 0x118;
96303231Sdim
97303231Sdim  memcpy(ResolverMem, ResolverCode, sizeof(ResolverCode));
98303231Sdim  memcpy(ResolverMem + ReentryFnAddrOffset, &ReentryFn, sizeof(ReentryFn));
99303231Sdim  memcpy(ResolverMem + CallbackMgrAddrOffset, &CallbackMgr,
100303231Sdim         sizeof(CallbackMgr));
101303231Sdim}
102303231Sdim
103303231Sdimvoid OrcAArch64::writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
104303231Sdim                                  unsigned NumTrampolines) {
105303231Sdim
106303231Sdim  unsigned OffsetToPtr = alignTo(NumTrampolines * TrampolineSize, 8);
107303231Sdim
108303231Sdim  memcpy(TrampolineMem + OffsetToPtr, &ResolverAddr, sizeof(void *));
109303231Sdim
110303231Sdim  // OffsetToPtr is actually the offset from the PC for the 2nd instruction, so
111303231Sdim  // subtract 32-bits.
112303231Sdim  OffsetToPtr -= 4;
113303231Sdim
114303231Sdim  uint32_t *Trampolines = reinterpret_cast<uint32_t *>(TrampolineMem);
115303231Sdim
116303231Sdim  for (unsigned I = 0; I < NumTrampolines; ++I, OffsetToPtr -= TrampolineSize) {
117303231Sdim    Trampolines[3 * I + 0] = 0xaa1e03f1;                      // mov x17, x30
118327952Sdim    Trampolines[3 * I + 1] = 0x58000010 | (OffsetToPtr << 3); // adr x16, Lptr
119303231Sdim    Trampolines[3 * I + 2] = 0xd63f0200;                      // blr x16
120303231Sdim  }
121303231Sdim
122303231Sdim}
123303231Sdim
124303231SdimError OrcAArch64::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
125303231Sdim                                         unsigned MinStubs,
126303231Sdim                                         void *InitialPtrVal) {
127303231Sdim  // Stub format is:
128303231Sdim  //
129303231Sdim  // .section __orc_stubs
130303231Sdim  // stub1:
131303231Sdim  //                 ldr     x0, ptr1       ; PC-rel load of ptr1
132303231Sdim  //                 br      x0             ; Jump to resolver
133303231Sdim  // stub2:
134303231Sdim  //                 ldr     x0, ptr2       ; PC-rel load of ptr2
135303231Sdim  //                 br      x0             ; Jump to resolver
136303231Sdim  //
137303231Sdim  // ...
138303231Sdim  //
139303231Sdim  // .section __orc_ptrs
140303231Sdim  // ptr1:
141303231Sdim  //                 .quad 0x0
142303231Sdim  // ptr2:
143303231Sdim  //                 .quad 0x0
144303231Sdim  //
145303231Sdim  // ...
146303231Sdim
147303231Sdim  const unsigned StubSize = IndirectStubsInfo::StubSize;
148303231Sdim
149303231Sdim  // Emit at least MinStubs, rounded up to fill the pages allocated.
150353358Sdim  static const unsigned PageSize = sys::Process::getPageSizeEstimate();
151303231Sdim  unsigned NumPages = ((MinStubs * StubSize) + (PageSize - 1)) / PageSize;
152303231Sdim  unsigned NumStubs = (NumPages * PageSize) / StubSize;
153303231Sdim
154303231Sdim  // Allocate memory for stubs and pointers in one call.
155303231Sdim  std::error_code EC;
156303231Sdim  auto StubsMem = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
157303231Sdim      2 * NumPages * PageSize, nullptr,
158303231Sdim      sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
159303231Sdim
160303231Sdim  if (EC)
161303231Sdim    return errorCodeToError(EC);
162303231Sdim
163303231Sdim  // Create separate MemoryBlocks representing the stubs and pointers.
164303231Sdim  sys::MemoryBlock StubsBlock(StubsMem.base(), NumPages * PageSize);
165303231Sdim  sys::MemoryBlock PtrsBlock(static_cast<char *>(StubsMem.base()) +
166303231Sdim                                 NumPages * PageSize,
167303231Sdim                             NumPages * PageSize);
168303231Sdim
169303231Sdim  // Populate the stubs page stubs and mark it executable.
170303231Sdim  uint64_t *Stub = reinterpret_cast<uint64_t *>(StubsBlock.base());
171303231Sdim  uint64_t PtrOffsetField = static_cast<uint64_t>(NumPages * PageSize)
172303231Sdim                            << 3;
173303231Sdim
174303231Sdim  for (unsigned I = 0; I < NumStubs; ++I)
175303231Sdim    Stub[I] = 0xd61f020058000010 | PtrOffsetField;
176303231Sdim
177303231Sdim  if (auto EC = sys::Memory::protectMappedMemory(
178303231Sdim          StubsBlock, sys::Memory::MF_READ | sys::Memory::MF_EXEC))
179303231Sdim    return errorCodeToError(EC);
180303231Sdim
181303231Sdim  // Initialize all pointers to point at FailureAddress.
182303231Sdim  void **Ptr = reinterpret_cast<void **>(PtrsBlock.base());
183303231Sdim  for (unsigned I = 0; I < NumStubs; ++I)
184303231Sdim    Ptr[I] = InitialPtrVal;
185303231Sdim
186303231Sdim  StubsInfo = IndirectStubsInfo(NumStubs, std::move(StubsMem));
187303231Sdim
188303231Sdim  return Error::success();
189303231Sdim}
190303231Sdim
191303231Sdimvoid OrcX86_64_Base::writeTrampolines(uint8_t *TrampolineMem,
192303231Sdim                                      void *ResolverAddr,
193303231Sdim                                      unsigned NumTrampolines) {
194303231Sdim
195303231Sdim  unsigned OffsetToPtr = NumTrampolines * TrampolineSize;
196303231Sdim
197303231Sdim  memcpy(TrampolineMem + OffsetToPtr, &ResolverAddr, sizeof(void *));
198303231Sdim
199303231Sdim  uint64_t *Trampolines = reinterpret_cast<uint64_t *>(TrampolineMem);
200303231Sdim  uint64_t CallIndirPCRel = 0xf1c40000000015ff;
201303231Sdim
202303231Sdim  for (unsigned I = 0; I < NumTrampolines; ++I, OffsetToPtr -= TrampolineSize)
203303231Sdim    Trampolines[I] = CallIndirPCRel | ((OffsetToPtr - 6) << 16);
204303231Sdim}
205303231Sdim
206303231SdimError OrcX86_64_Base::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
207303231Sdim                                             unsigned MinStubs,
208303231Sdim                                             void *InitialPtrVal) {
209303231Sdim  // Stub format is:
210303231Sdim  //
211303231Sdim  // .section __orc_stubs
212303231Sdim  // stub1:
213303231Sdim  //                 jmpq    *ptr1(%rip)
214303231Sdim  //                 .byte   0xC4         ; <- Invalid opcode padding.
215303231Sdim  //                 .byte   0xF1
216303231Sdim  // stub2:
217303231Sdim  //                 jmpq    *ptr2(%rip)
218303231Sdim  //
219303231Sdim  // ...
220303231Sdim  //
221303231Sdim  // .section __orc_ptrs
222303231Sdim  // ptr1:
223303231Sdim  //                 .quad 0x0
224303231Sdim  // ptr2:
225303231Sdim  //                 .quad 0x0
226303231Sdim  //
227303231Sdim  // ...
228303231Sdim
229303231Sdim  const unsigned StubSize = IndirectStubsInfo::StubSize;
230303231Sdim
231303231Sdim  // Emit at least MinStubs, rounded up to fill the pages allocated.
232353358Sdim  static const unsigned PageSize = sys::Process::getPageSizeEstimate();
233303231Sdim  unsigned NumPages = ((MinStubs * StubSize) + (PageSize - 1)) / PageSize;
234303231Sdim  unsigned NumStubs = (NumPages * PageSize) / StubSize;
235303231Sdim
236303231Sdim  // Allocate memory for stubs and pointers in one call.
237303231Sdim  std::error_code EC;
238303231Sdim  auto StubsMem = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
239303231Sdim      2 * NumPages * PageSize, nullptr,
240303231Sdim      sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
241303231Sdim
242303231Sdim  if (EC)
243303231Sdim    return errorCodeToError(EC);
244303231Sdim
245303231Sdim  // Create separate MemoryBlocks representing the stubs and pointers.
246303231Sdim  sys::MemoryBlock StubsBlock(StubsMem.base(), NumPages * PageSize);
247303231Sdim  sys::MemoryBlock PtrsBlock(static_cast<char *>(StubsMem.base()) +
248303231Sdim                                 NumPages * PageSize,
249303231Sdim                             NumPages * PageSize);
250303231Sdim
251303231Sdim  // Populate the stubs page stubs and mark it executable.
252303231Sdim  uint64_t *Stub = reinterpret_cast<uint64_t *>(StubsBlock.base());
253303231Sdim  uint64_t PtrOffsetField = static_cast<uint64_t>(NumPages * PageSize - 6)
254303231Sdim                            << 16;
255303231Sdim  for (unsigned I = 0; I < NumStubs; ++I)
256303231Sdim    Stub[I] = 0xF1C40000000025ff | PtrOffsetField;
257303231Sdim
258303231Sdim  if (auto EC = sys::Memory::protectMappedMemory(
259303231Sdim          StubsBlock, sys::Memory::MF_READ | sys::Memory::MF_EXEC))
260303231Sdim    return errorCodeToError(EC);
261303231Sdim
262303231Sdim  // Initialize all pointers to point at FailureAddress.
263303231Sdim  void **Ptr = reinterpret_cast<void **>(PtrsBlock.base());
264303231Sdim  for (unsigned I = 0; I < NumStubs; ++I)
265303231Sdim    Ptr[I] = InitialPtrVal;
266303231Sdim
267303231Sdim  StubsInfo = IndirectStubsInfo(NumStubs, std::move(StubsMem));
268303231Sdim
269303231Sdim  return Error::success();
270303231Sdim}
271303231Sdim
272303231Sdimvoid OrcX86_64_SysV::writeResolverCode(uint8_t *ResolverMem,
273303231Sdim                                       JITReentryFn ReentryFn,
274303231Sdim                                       void *CallbackMgr) {
275303231Sdim
276303231Sdim  const uint8_t ResolverCode[] = {
277303231Sdim      // resolver_entry:
278303231Sdim      0x55,                                     // 0x00: pushq     %rbp
279303231Sdim      0x48, 0x89, 0xe5,                         // 0x01: movq      %rsp, %rbp
280303231Sdim      0x50,                                     // 0x04: pushq     %rax
281303231Sdim      0x53,                                     // 0x05: pushq     %rbx
282303231Sdim      0x51,                                     // 0x06: pushq     %rcx
283303231Sdim      0x52,                                     // 0x07: pushq     %rdx
284303231Sdim      0x56,                                     // 0x08: pushq     %rsi
285303231Sdim      0x57,                                     // 0x09: pushq     %rdi
286303231Sdim      0x41, 0x50,                               // 0x0a: pushq     %r8
287303231Sdim      0x41, 0x51,                               // 0x0c: pushq     %r9
288303231Sdim      0x41, 0x52,                               // 0x0e: pushq     %r10
289303231Sdim      0x41, 0x53,                               // 0x10: pushq     %r11
290303231Sdim      0x41, 0x54,                               // 0x12: pushq     %r12
291303231Sdim      0x41, 0x55,                               // 0x14: pushq     %r13
292303231Sdim      0x41, 0x56,                               // 0x16: pushq     %r14
293303231Sdim      0x41, 0x57,                               // 0x18: pushq     %r15
294303231Sdim      0x48, 0x81, 0xec, 0x08, 0x02, 0x00, 0x00, // 0x1a: subq      0x208, %rsp
295303231Sdim      0x48, 0x0f, 0xae, 0x04, 0x24,             // 0x21: fxsave64  (%rsp)
296303231Sdim      0x48, 0xbf,                               // 0x26: movabsq   <CBMgr>, %rdi
297303231Sdim
298303231Sdim      // 0x28: Callback manager addr.
299303231Sdim      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300303231Sdim
301303231Sdim      0x48, 0x8b, 0x75, 0x08,                   // 0x30: movq      8(%rbp), %rsi
302303231Sdim      0x48, 0x83, 0xee, 0x06,                   // 0x34: subq      $6, %rsi
303303231Sdim      0x48, 0xb8,                               // 0x38: movabsq   <REntry>, %rax
304303231Sdim
305303231Sdim      // 0x3a: JIT re-entry fn addr:
306303231Sdim      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
307303231Sdim
308303231Sdim      0xff, 0xd0,                               // 0x42: callq     *%rax
309303231Sdim      0x48, 0x89, 0x45, 0x08,                   // 0x44: movq      %rax, 8(%rbp)
310303231Sdim      0x48, 0x0f, 0xae, 0x0c, 0x24,             // 0x48: fxrstor64 (%rsp)
311303231Sdim      0x48, 0x81, 0xc4, 0x08, 0x02, 0x00, 0x00, // 0x4d: addq      0x208, %rsp
312303231Sdim      0x41, 0x5f,                               // 0x54: popq      %r15
313303231Sdim      0x41, 0x5e,                               // 0x56: popq      %r14
314303231Sdim      0x41, 0x5d,                               // 0x58: popq      %r13
315303231Sdim      0x41, 0x5c,                               // 0x5a: popq      %r12
316303231Sdim      0x41, 0x5b,                               // 0x5c: popq      %r11
317303231Sdim      0x41, 0x5a,                               // 0x5e: popq      %r10
318303231Sdim      0x41, 0x59,                               // 0x60: popq      %r9
319303231Sdim      0x41, 0x58,                               // 0x62: popq      %r8
320303231Sdim      0x5f,                                     // 0x64: popq      %rdi
321303231Sdim      0x5e,                                     // 0x65: popq      %rsi
322303231Sdim      0x5a,                                     // 0x66: popq      %rdx
323303231Sdim      0x59,                                     // 0x67: popq      %rcx
324303231Sdim      0x5b,                                     // 0x68: popq      %rbx
325303231Sdim      0x58,                                     // 0x69: popq      %rax
326303231Sdim      0x5d,                                     // 0x6a: popq      %rbp
327303231Sdim      0xc3,                                     // 0x6b: retq
328303231Sdim  };
329303231Sdim
330303231Sdim  const unsigned ReentryFnAddrOffset = 0x3a;
331303231Sdim  const unsigned CallbackMgrAddrOffset = 0x28;
332303231Sdim
333303231Sdim  memcpy(ResolverMem, ResolverCode, sizeof(ResolverCode));
334303231Sdim  memcpy(ResolverMem + ReentryFnAddrOffset, &ReentryFn, sizeof(ReentryFn));
335303231Sdim  memcpy(ResolverMem + CallbackMgrAddrOffset, &CallbackMgr,
336303231Sdim         sizeof(CallbackMgr));
337303231Sdim}
338303231Sdim
339303231Sdimvoid OrcX86_64_Win32::writeResolverCode(uint8_t *ResolverMem,
340303231Sdim                                        JITReentryFn ReentryFn,
341303231Sdim                                        void *CallbackMgr) {
342303231Sdim
343303231Sdim  // resolverCode is similar to OrcX86_64 with differences specific to windows x64 calling convention:
344303231Sdim  // arguments go into rcx, rdx and come in reverse order, shadow space allocation on stack
345303231Sdim  const uint8_t ResolverCode[] = {
346303231Sdim      // resolver_entry:
347303231Sdim      0x55,                                      // 0x00: pushq     %rbp
348303231Sdim      0x48, 0x89, 0xe5,                          // 0x01: movq      %rsp, %rbp
349303231Sdim      0x50,                                      // 0x04: pushq     %rax
350303231Sdim      0x53,                                      // 0x05: pushq     %rbx
351303231Sdim      0x51,                                      // 0x06: pushq     %rcx
352303231Sdim      0x52,                                      // 0x07: pushq     %rdx
353303231Sdim      0x56,                                      // 0x08: pushq     %rsi
354303231Sdim      0x57,                                      // 0x09: pushq     %rdi
355303231Sdim      0x41, 0x50,                                // 0x0a: pushq     %r8
356303231Sdim      0x41, 0x51,                                // 0x0c: pushq     %r9
357303231Sdim      0x41, 0x52,                                // 0x0e: pushq     %r10
358303231Sdim      0x41, 0x53,                                // 0x10: pushq     %r11
359303231Sdim      0x41, 0x54,                                // 0x12: pushq     %r12
360303231Sdim      0x41, 0x55,                                // 0x14: pushq     %r13
361303231Sdim      0x41, 0x56,                                // 0x16: pushq     %r14
362303231Sdim      0x41, 0x57,                                // 0x18: pushq     %r15
363303231Sdim      0x48, 0x81, 0xec, 0x08, 0x02, 0x00, 0x00,  // 0x1a: subq      0x208, %rsp
364303231Sdim      0x48, 0x0f, 0xae, 0x04, 0x24,              // 0x21: fxsave64  (%rsp)
365303231Sdim
366303231Sdim      0x48, 0xb9,                                // 0x26: movabsq   <CBMgr>, %rcx
367303231Sdim      // 0x28: Callback manager addr.
368303231Sdim      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
369303231Sdim
370303231Sdim      0x48, 0x8B, 0x55, 0x08,                    // 0x30: mov       rdx, [rbp+0x8]
371303231Sdim      0x48, 0x83, 0xea, 0x06,                    // 0x34: sub       rdx, 0x6
372303231Sdim
373303231Sdim      0x48, 0xb8,                                // 0x38: movabsq   <REntry>, %rax
374303231Sdim      // 0x3a: JIT re-entry fn addr:
375303231Sdim      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
376303231Sdim
377303231Sdim      // 0x42: sub       rsp, 0x20 (Allocate shadow space)
378303231Sdim      0x48, 0x83, 0xEC, 0x20,
379303231Sdim      0xff, 0xd0,                                // 0x46: callq     *%rax
380303231Sdim
381303231Sdim      // 0x48: add       rsp, 0x20 (Free shadow space)
382303231Sdim      0x48, 0x83, 0xC4, 0x20,
383303231Sdim
384303231Sdim      0x48, 0x89, 0x45, 0x08,                    // 0x4C: movq      %rax, 8(%rbp)
385303231Sdim      0x48, 0x0f, 0xae, 0x0c, 0x24,              // 0x50: fxrstor64 (%rsp)
386303231Sdim      0x48, 0x81, 0xc4, 0x08, 0x02, 0x00, 0x00,  // 0x55: addq      0x208, %rsp
387303231Sdim      0x41, 0x5f,                                // 0x5C: popq      %r15
388303231Sdim      0x41, 0x5e,                                // 0x5E: popq      %r14
389303231Sdim      0x41, 0x5d,                                // 0x60: popq      %r13
390303231Sdim      0x41, 0x5c,                                // 0x62: popq      %r12
391303231Sdim      0x41, 0x5b,                                // 0x64: popq      %r11
392303231Sdim      0x41, 0x5a,                                // 0x66: popq      %r10
393303231Sdim      0x41, 0x59,                                // 0x68: popq      %r9
394303231Sdim      0x41, 0x58,                                // 0x6a: popq      %r8
395303231Sdim      0x5f,                                      // 0x6c: popq      %rdi
396303231Sdim      0x5e,                                      // 0x6d: popq      %rsi
397303231Sdim      0x5a,                                      // 0x6e: popq      %rdx
398303231Sdim      0x59,                                      // 0x6f: popq      %rcx
399303231Sdim      0x5b,                                      // 0x70: popq      %rbx
400303231Sdim      0x58,                                      // 0x71: popq      %rax
401303231Sdim      0x5d,                                      // 0x72: popq      %rbp
402303231Sdim      0xc3,                                      // 0x73: retq
403303231Sdim  };
404303231Sdim
405303231Sdim
406303231Sdim  const unsigned ReentryFnAddrOffset = 0x3a;
407303231Sdim  const unsigned CallbackMgrAddrOffset = 0x28;
408303231Sdim
409303231Sdim  memcpy(ResolverMem, ResolverCode, sizeof(ResolverCode));
410303231Sdim  memcpy(ResolverMem + ReentryFnAddrOffset, &ReentryFn, sizeof(ReentryFn));
411303231Sdim  memcpy(ResolverMem + CallbackMgrAddrOffset, &CallbackMgr,
412303231Sdim         sizeof(CallbackMgr));
413303231Sdim}
414303231Sdim
415303231Sdimvoid OrcI386::writeResolverCode(uint8_t *ResolverMem, JITReentryFn ReentryFn,
416303231Sdim                                void *CallbackMgr) {
417303231Sdim
418303231Sdim  const uint8_t ResolverCode[] = {
419303231Sdim      // resolver_entry:
420303231Sdim      0x55,                               // 0x00: pushl    %ebp
421303231Sdim      0x89, 0xe5,                         // 0x01: movl     %esp, %ebp
422303231Sdim      0x54,                               // 0x03: pushl    %esp
423303231Sdim      0x83, 0xe4, 0xf0,                   // 0x04: andl     $-0x10, %esp
424303231Sdim      0x50,                               // 0x07: pushl    %eax
425303231Sdim      0x53,                               // 0x08: pushl    %ebx
426303231Sdim      0x51,                               // 0x09: pushl    %ecx
427303231Sdim      0x52,                               // 0x0a: pushl    %edx
428303231Sdim      0x56,                               // 0x0b: pushl    %esi
429303231Sdim      0x57,                               // 0x0c: pushl    %edi
430303231Sdim      0x81, 0xec, 0x18, 0x02, 0x00, 0x00, // 0x0d: subl     $0x218, %esp
431303231Sdim      0x0f, 0xae, 0x44, 0x24, 0x10,       // 0x13: fxsave   0x10(%esp)
432303231Sdim      0x8b, 0x75, 0x04,                   // 0x18: movl     0x4(%ebp), %esi
433303231Sdim      0x83, 0xee, 0x05,                   // 0x1b: subl     $0x5, %esi
434303231Sdim      0x89, 0x74, 0x24, 0x04,             // 0x1e: movl     %esi, 0x4(%esp)
435303231Sdim      0xc7, 0x04, 0x24, 0x00, 0x00, 0x00,
436303231Sdim      0x00,                               // 0x22: movl     <cbmgr>, (%esp)
437303231Sdim      0xb8, 0x00, 0x00, 0x00, 0x00,       // 0x29: movl     <reentry>, %eax
438303231Sdim      0xff, 0xd0,                         // 0x2e: calll    *%eax
439303231Sdim      0x89, 0x45, 0x04,                   // 0x30: movl     %eax, 0x4(%ebp)
440303231Sdim      0x0f, 0xae, 0x4c, 0x24, 0x10,       // 0x33: fxrstor  0x10(%esp)
441303231Sdim      0x81, 0xc4, 0x18, 0x02, 0x00, 0x00, // 0x38: addl     $0x218, %esp
442303231Sdim      0x5f,                               // 0x3e: popl     %edi
443303231Sdim      0x5e,                               // 0x3f: popl     %esi
444303231Sdim      0x5a,                               // 0x40: popl     %edx
445303231Sdim      0x59,                               // 0x41: popl     %ecx
446303231Sdim      0x5b,                               // 0x42: popl     %ebx
447303231Sdim      0x58,                               // 0x43: popl     %eax
448303231Sdim      0x8b, 0x65, 0xfc,                   // 0x44: movl     -0x4(%ebp), %esp
449303231Sdim      0x5d,                               // 0x48: popl     %ebp
450303231Sdim      0xc3                                // 0x49: retl
451303231Sdim  };
452303231Sdim
453303231Sdim  const unsigned ReentryFnAddrOffset = 0x2a;
454303231Sdim  const unsigned CallbackMgrAddrOffset = 0x25;
455303231Sdim
456303231Sdim  memcpy(ResolverMem, ResolverCode, sizeof(ResolverCode));
457303231Sdim  memcpy(ResolverMem + ReentryFnAddrOffset, &ReentryFn, sizeof(ReentryFn));
458303231Sdim  memcpy(ResolverMem + CallbackMgrAddrOffset, &CallbackMgr,
459303231Sdim         sizeof(CallbackMgr));
460303231Sdim}
461303231Sdim
462303231Sdimvoid OrcI386::writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
463303231Sdim                               unsigned NumTrampolines) {
464303231Sdim
465303231Sdim  uint64_t CallRelImm = 0xF1C4C400000000e8;
466303231Sdim  uint64_t Resolver = reinterpret_cast<uint64_t>(ResolverAddr);
467303231Sdim  uint64_t ResolverRel =
468303231Sdim      Resolver - reinterpret_cast<uint64_t>(TrampolineMem) - 5;
469303231Sdim
470303231Sdim  uint64_t *Trampolines = reinterpret_cast<uint64_t *>(TrampolineMem);
471303231Sdim  for (unsigned I = 0; I < NumTrampolines; ++I, ResolverRel -= TrampolineSize)
472303231Sdim    Trampolines[I] = CallRelImm | (ResolverRel << 8);
473303231Sdim}
474303231Sdim
475303231SdimError OrcI386::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
476303231Sdim                                      unsigned MinStubs, void *InitialPtrVal) {
477303231Sdim  // Stub format is:
478303231Sdim  //
479303231Sdim  // .section __orc_stubs
480303231Sdim  // stub1:
481303231Sdim  //                 jmpq    *ptr1
482303231Sdim  //                 .byte   0xC4         ; <- Invalid opcode padding.
483303231Sdim  //                 .byte   0xF1
484303231Sdim  // stub2:
485303231Sdim  //                 jmpq    *ptr2
486303231Sdim  //
487303231Sdim  // ...
488303231Sdim  //
489303231Sdim  // .section __orc_ptrs
490303231Sdim  // ptr1:
491303231Sdim  //                 .quad 0x0
492303231Sdim  // ptr2:
493303231Sdim  //                 .quad 0x0
494303231Sdim  //
495303231Sdim  // ...
496303231Sdim
497303231Sdim  const unsigned StubSize = IndirectStubsInfo::StubSize;
498303231Sdim
499303231Sdim  // Emit at least MinStubs, rounded up to fill the pages allocated.
500353358Sdim  static const unsigned PageSize = sys::Process::getPageSizeEstimate();
501303231Sdim  unsigned NumPages = ((MinStubs * StubSize) + (PageSize - 1)) / PageSize;
502303231Sdim  unsigned NumStubs = (NumPages * PageSize) / StubSize;
503303231Sdim
504303231Sdim  // Allocate memory for stubs and pointers in one call.
505303231Sdim  std::error_code EC;
506303231Sdim  auto StubsMem = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
507303231Sdim      2 * NumPages * PageSize, nullptr,
508303231Sdim      sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
509303231Sdim
510303231Sdim  if (EC)
511303231Sdim    return errorCodeToError(EC);
512303231Sdim
513303231Sdim  // Create separate MemoryBlocks representing the stubs and pointers.
514303231Sdim  sys::MemoryBlock StubsBlock(StubsMem.base(), NumPages * PageSize);
515303231Sdim  sys::MemoryBlock PtrsBlock(static_cast<char *>(StubsMem.base()) +
516303231Sdim                                 NumPages * PageSize,
517303231Sdim                             NumPages * PageSize);
518303231Sdim
519303231Sdim  // Populate the stubs page stubs and mark it executable.
520303231Sdim  uint64_t *Stub = reinterpret_cast<uint64_t *>(StubsBlock.base());
521303231Sdim  uint64_t PtrAddr = reinterpret_cast<uint64_t>(PtrsBlock.base());
522303231Sdim  for (unsigned I = 0; I < NumStubs; ++I, PtrAddr += 4)
523303231Sdim    Stub[I] = 0xF1C40000000025ff | (PtrAddr << 16);
524303231Sdim
525303231Sdim  if (auto EC = sys::Memory::protectMappedMemory(
526303231Sdim          StubsBlock, sys::Memory::MF_READ | sys::Memory::MF_EXEC))
527303231Sdim    return errorCodeToError(EC);
528303231Sdim
529303231Sdim  // Initialize all pointers to point at FailureAddress.
530303231Sdim  void **Ptr = reinterpret_cast<void **>(PtrsBlock.base());
531303231Sdim  for (unsigned I = 0; I < NumStubs; ++I)
532303231Sdim    Ptr[I] = InitialPtrVal;
533303231Sdim
534303231Sdim  StubsInfo = IndirectStubsInfo(NumStubs, std::move(StubsMem));
535303231Sdim
536303231Sdim  return Error::success();
537303231Sdim}
538303231Sdim
539344779Sdimvoid OrcMips32_Base::writeResolverCode(uint8_t *ResolverMem,
540344779Sdim                                       JITReentryFn ReentryFn,
541344779Sdim                                       void *CallbackMgr, bool isBigEndian) {
542344779Sdim
543344779Sdim  const uint32_t ResolverCode[] = {
544344779Sdim      // resolver_entry:
545344779Sdim      0x27bdff98,                    // 0x00: addiu $sp,$sp,-104
546344779Sdim      0xafa20000,                    // 0x04: sw $v0,0($sp)
547344779Sdim      0xafa30004,                    // 0x08: sw $v1,4($sp)
548344779Sdim      0xafa40008,                    // 0x0c: sw $a0,8($sp)
549344779Sdim      0xafa5000c,                    // 0x10: sw $a1,12($sp)
550344779Sdim      0xafa60010,                    // 0x14: sw $a2,16($sp)
551344779Sdim      0xafa70014,                    // 0x18: sw $a3,20($sp)
552344779Sdim      0xafb00018,                    // 0x1c: sw $s0,24($sp)
553344779Sdim      0xafb1001c,                    // 0x20: sw $s1,28($sp)
554344779Sdim      0xafb20020,                    // 0x24: sw $s2,32($sp)
555344779Sdim      0xafb30024,                    // 0x28: sw $s3,36($sp)
556344779Sdim      0xafb40028,                    // 0x2c: sw $s4,40($sp)
557344779Sdim      0xafb5002c,                    // 0x30: sw $s5,44($sp)
558344779Sdim      0xafb60030,                    // 0x34: sw $s6,48($sp)
559344779Sdim      0xafb70034,                    // 0x38: sw $s7,52($sp)
560344779Sdim      0xafa80038,                    // 0x3c: sw $t0,56($sp)
561344779Sdim      0xafa9003c,                    // 0x40: sw $t1,60($sp)
562344779Sdim      0xafaa0040,                    // 0x44: sw $t2,64($sp)
563344779Sdim      0xafab0044,                    // 0x48: sw $t3,68($sp)
564344779Sdim      0xafac0048,                    // 0x4c: sw $t4,72($sp)
565344779Sdim      0xafad004c,                    // 0x50: sw $t5,76($sp)
566344779Sdim      0xafae0050,                    // 0x54: sw $t6,80($sp)
567344779Sdim      0xafaf0054,                    // 0x58: sw $t7,84($sp)
568344779Sdim      0xafb80058,                    // 0x5c: sw $t8,88($sp)
569344779Sdim      0xafb9005c,                    // 0x60: sw $t9,92($sp)
570344779Sdim      0xafbe0060,                    // 0x64: sw $fp,96($sp)
571344779Sdim      0xafbf0064,                    // 0x68: sw $ra,100($sp)
572344779Sdim
573344779Sdim      // Callback manager addr.
574344779Sdim      0x00000000,                    // 0x6c: lui $a0,callbackmgr
575344779Sdim      0x00000000,                    // 0x70: addiu $a0,$a0,callbackmgr
576344779Sdim
577344779Sdim      0x03e02825,                    // 0x74: move $a1, $ra
578344779Sdim      0x24a5ffec,                    // 0x78: addiu $a1,$a1,-20
579344779Sdim
580344779Sdim      // JIT re-entry fn addr:
581344779Sdim      0x00000000,                    // 0x7c: lui $t9,reentry
582344779Sdim      0x00000000,                    // 0x80: addiu $t9,$t9,reentry
583344779Sdim
584344779Sdim      0x0320f809,                    // 0x84: jalr $t9
585344779Sdim      0x00000000,                    // 0x88: nop
586344779Sdim      0x8fbf0064,                    // 0x8c: lw $ra,100($sp)
587344779Sdim      0x8fbe0060,                    // 0x90: lw $fp,96($sp)
588344779Sdim      0x8fb9005c,                    // 0x94: lw $t9,92($sp)
589344779Sdim      0x8fb80058,                    // 0x98: lw $t8,88($sp)
590344779Sdim      0x8faf0054,                    // 0x9c: lw $t7,84($sp)
591344779Sdim      0x8fae0050,                    // 0xa0: lw $t6,80($sp)
592344779Sdim      0x8fad004c,                    // 0xa4: lw $t5,76($sp)
593344779Sdim      0x8fac0048,                    // 0xa8: lw $t4,72($sp)
594344779Sdim      0x8fab0044,                    // 0xac: lw $t3,68($sp)
595344779Sdim      0x8faa0040,                    // 0xb0: lw $t2,64($sp)
596344779Sdim      0x8fa9003c,                    // 0xb4: lw $t1,60($sp)
597344779Sdim      0x8fa80038,                    // 0xb8: lw $t0,56($sp)
598344779Sdim      0x8fb70034,                    // 0xbc: lw $s7,52($sp)
599344779Sdim      0x8fb60030,                    // 0xc0: lw $s6,48($sp)
600344779Sdim      0x8fb5002c,                    // 0xc4: lw $s5,44($sp)
601344779Sdim      0x8fb40028,                    // 0xc8: lw $s4,40($sp)
602344779Sdim      0x8fb30024,                    // 0xcc: lw $s3,36($sp)
603344779Sdim      0x8fb20020,                    // 0xd0: lw $s2,32($sp)
604344779Sdim      0x8fb1001c,                    // 0xd4: lw $s1,28($sp)
605344779Sdim      0x8fb00018,                    // 0xd8: lw $s0,24($sp)
606344779Sdim      0x8fa70014,                    // 0xdc: lw $a3,20($sp)
607344779Sdim      0x8fa60010,                    // 0xe0: lw $a2,16($sp)
608344779Sdim      0x8fa5000c,                    // 0xe4: lw $a1,12($sp)
609344779Sdim      0x8fa40008,                    // 0xe8: lw $a0,8($sp)
610344779Sdim      0x27bd0068,                    // 0xec: addiu $sp,$sp,104
611344779Sdim      0x0300f825,                    // 0xf0: move $ra, $t8
612344779Sdim      0x03200008,                    // 0xf4: jr $t9
613344779Sdim      0x00000000,                    // 0xf8: move $t9, $v0/v1
614344779Sdim  };
615344779Sdim
616344779Sdim  const unsigned ReentryFnAddrOffset = 0x7c;   // JIT re-entry fn addr lui
617344779Sdim  const unsigned CallbackMgrAddrOffset = 0x6c; // Callback manager addr lui
618344779Sdim  const unsigned Offsett = 0xf8;
619344779Sdim
620344779Sdim  memcpy(ResolverMem, ResolverCode, sizeof(ResolverCode));
621344779Sdim
622344779Sdim  // Depending on endian return value will be in v0 or v1.
623344779Sdim  uint32_t MoveVxT9 = isBigEndian ? 0x0060c825 : 0x0040c825;
624344779Sdim  memcpy(ResolverMem + Offsett, &MoveVxT9, sizeof(MoveVxT9));
625344779Sdim
626344779Sdim  uint64_t CallMgrAddr = reinterpret_cast<uint64_t>(CallbackMgr);
627344779Sdim  uint32_t CallMgrLUi = 0x3c040000 | (((CallMgrAddr + 0x8000) >> 16) & 0xFFFF);
628344779Sdim  uint32_t CallMgrADDiu = 0x24840000 | ((CallMgrAddr) & 0xFFFF);
629344779Sdim  memcpy(ResolverMem + CallbackMgrAddrOffset, &CallMgrLUi, sizeof(CallMgrLUi));
630344779Sdim  memcpy(ResolverMem + CallbackMgrAddrOffset + 4, &CallMgrADDiu,
631344779Sdim         sizeof(CallMgrADDiu));
632344779Sdim
633344779Sdim  uint64_t ReentryAddr = reinterpret_cast<uint64_t>(ReentryFn);
634344779Sdim  uint32_t ReentryLUi = 0x3c190000 | (((ReentryAddr + 0x8000) >> 16) & 0xFFFF);
635344779Sdim  uint32_t ReentryADDiu = 0x27390000 | ((ReentryAddr) & 0xFFFF);
636344779Sdim  memcpy(ResolverMem + ReentryFnAddrOffset, &ReentryLUi, sizeof(ReentryLUi));
637344779Sdim  memcpy(ResolverMem + ReentryFnAddrOffset + 4, &ReentryADDiu,
638344779Sdim         sizeof(ReentryADDiu));
639344779Sdim}
640344779Sdim
641344779Sdimvoid OrcMips32_Base::writeTrampolines(uint8_t *TrampolineMem,
642344779Sdim                                      void *ResolverAddr,
643344779Sdim                                      unsigned NumTrampolines) {
644344779Sdim
645344779Sdim  uint32_t *Trampolines = reinterpret_cast<uint32_t *>(TrampolineMem);
646344779Sdim  uint64_t ResolveAddr = reinterpret_cast<uint64_t>(ResolverAddr);
647344779Sdim  uint32_t RHiAddr = ((ResolveAddr + 0x8000) >> 16);
648344779Sdim
649344779Sdim  for (unsigned I = 0; I < NumTrampolines; ++I) {
650344779Sdim    Trampolines[5 * I + 0] = 0x03e0c025;                           // move $t8,$ra
651344779Sdim    Trampolines[5 * I + 1] = 0x3c190000 | (RHiAddr & 0xFFFF);      // lui $t9,resolveAddr
652344779Sdim    Trampolines[5 * I + 2] = 0x27390000 | (ResolveAddr & 0xFFFF);  // addiu $t9,$t9,resolveAddr
653344779Sdim    Trampolines[5 * I + 3] = 0x0320f809;                           // jalr $t9
654344779Sdim    Trampolines[5 * I + 4] = 0x00000000;                           // nop
655344779Sdim  }
656344779Sdim}
657344779Sdim
658344779SdimError OrcMips32_Base::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
659344779Sdim                                             unsigned MinStubs,
660344779Sdim                                             void *InitialPtrVal) {
661344779Sdim  // Stub format is:
662344779Sdim  //
663344779Sdim  // .section __orc_stubs
664344779Sdim  // stub1:
665344779Sdim  //                 lui $t9, ptr1
666344779Sdim  //                 lw $t9, %lo(ptr1)($t9)
667344779Sdim  //                 jr $t9
668344779Sdim  // stub2:
669344779Sdim  //                 lui $t9, ptr2
670344779Sdim  //                 lw $t9,%lo(ptr1)($t9)
671344779Sdim  //                 jr $t9
672344779Sdim  //
673344779Sdim  // ...
674344779Sdim  //
675344779Sdim  // .section __orc_ptrs
676344779Sdim  // ptr1:
677344779Sdim  //                 .word 0x0
678344779Sdim  // ptr2:
679344779Sdim  //                 .word 0x0
680344779Sdim  //
681344779Sdim  // ...
682344779Sdim
683344779Sdim  const unsigned StubSize = IndirectStubsInfo::StubSize;
684344779Sdim
685344779Sdim  // Emit at least MinStubs, rounded up to fill the pages allocated.
686353358Sdim  static const unsigned PageSize = sys::Process::getPageSizeEstimate();
687344779Sdim  unsigned NumPages = ((MinStubs * StubSize) + (PageSize - 1)) / PageSize;
688344779Sdim  unsigned NumStubs = (NumPages * PageSize) / StubSize;
689344779Sdim
690344779Sdim  // Allocate memory for stubs and pointers in one call.
691344779Sdim  std::error_code EC;
692344779Sdim  auto StubsMem = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
693344779Sdim      2 * NumPages * PageSize, nullptr,
694344779Sdim      sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
695344779Sdim
696344779Sdim  if (EC)
697344779Sdim    return errorCodeToError(EC);
698344779Sdim
699344779Sdim  // Create separate MemoryBlocks representing the stubs and pointers.
700344779Sdim  sys::MemoryBlock StubsBlock(StubsMem.base(), NumPages * PageSize);
701344779Sdim  sys::MemoryBlock PtrsBlock(static_cast<char *>(StubsMem.base()) +
702344779Sdim                                 NumPages * PageSize,
703344779Sdim                             NumPages * PageSize);
704344779Sdim
705344779Sdim  // Populate the stubs page stubs and mark it executable.
706344779Sdim  uint32_t *Stub = reinterpret_cast<uint32_t *>(StubsBlock.base());
707344779Sdim  uint64_t PtrAddr = reinterpret_cast<uint64_t>(Stub) + NumPages * PageSize;
708344779Sdim
709344779Sdim  for (unsigned I = 0; I < NumStubs; ++I) {
710344779Sdim    uint32_t HiAddr = ((PtrAddr + 0x8000) >> 16);
711344779Sdim    Stub[4 * I + 0] = 0x3c190000 | (HiAddr & 0xFFFF);  // lui $t9,ptr1
712344779Sdim    Stub[4 * I + 1] = 0x8f390000 | (PtrAddr & 0xFFFF); // lw $t9,%lo(ptr1)($t9)
713344779Sdim    Stub[4 * I + 2] = 0x03200008;                      // jr $t9
714344779Sdim    Stub[4 * I + 3] = 0x00000000;                      // nop
715344779Sdim    PtrAddr += 4;
716344779Sdim  }
717344779Sdim
718344779Sdim  if (auto EC = sys::Memory::protectMappedMemory(
719344779Sdim          StubsBlock, sys::Memory::MF_READ | sys::Memory::MF_EXEC))
720344779Sdim    return errorCodeToError(EC);
721344779Sdim
722344779Sdim  // Initialize all pointers to point at FailureAddress.
723344779Sdim  void **Ptr = reinterpret_cast<void **>(PtrsBlock.base());
724344779Sdim  for (unsigned I = 0; I < NumStubs; ++I)
725344779Sdim    Ptr[I] = InitialPtrVal;
726344779Sdim
727344779Sdim  StubsInfo = IndirectStubsInfo(NumStubs, std::move(StubsMem));
728344779Sdim
729344779Sdim  return Error::success();
730344779Sdim}
731344779Sdim
732344779Sdimvoid OrcMips64::writeResolverCode(uint8_t *ResolverMem, JITReentryFn ReentryFn,
733344779Sdim                                  void *CallbackMgr) {
734344779Sdim
735344779Sdim  const uint32_t ResolverCode[] = {
736344779Sdim      //resolver_entry:
737344779Sdim      0x67bdff30,                     // 0x00: daddiu $sp,$sp,-208
738344779Sdim      0xffa20000,                     // 0x04: sd v0,0(sp)
739344779Sdim      0xffa30008,                     // 0x08: sd v1,8(sp)
740344779Sdim      0xffa40010,                     // 0x0c: sd a0,16(sp)
741344779Sdim      0xffa50018,                     // 0x10: sd a1,24(sp)
742344779Sdim      0xffa60020,                     // 0x14: sd a2,32(sp)
743344779Sdim      0xffa70028,                     // 0x18: sd a3,40(sp)
744344779Sdim      0xffa80030,                     // 0x1c: sd a4,48(sp)
745344779Sdim      0xffa90038,                     // 0x20: sd a5,56(sp)
746344779Sdim      0xffaa0040,                     // 0x24: sd a6,64(sp)
747344779Sdim      0xffab0048,                     // 0x28: sd a7,72(sp)
748344779Sdim      0xffac0050,                     // 0x2c: sd t0,80(sp)
749344779Sdim      0xffad0058,                     // 0x30: sd t1,88(sp)
750344779Sdim      0xffae0060,                     // 0x34: sd t2,96(sp)
751344779Sdim      0xffaf0068,                     // 0x38: sd t3,104(sp)
752344779Sdim      0xffb00070,                     // 0x3c: sd s0,112(sp)
753344779Sdim      0xffb10078,                     // 0x40: sd s1,120(sp)
754344779Sdim      0xffb20080,                     // 0x44: sd s2,128(sp)
755344779Sdim      0xffb30088,                     // 0x48: sd s3,136(sp)
756344779Sdim      0xffb40090,                     // 0x4c: sd s4,144(sp)
757344779Sdim      0xffb50098,                     // 0x50: sd s5,152(sp)
758344779Sdim      0xffb600a0,                     // 0x54: sd s6,160(sp)
759344779Sdim      0xffb700a8,                     // 0x58: sd s7,168(sp)
760344779Sdim      0xffb800b0,                     // 0x5c: sd t8,176(sp)
761344779Sdim      0xffb900b8,                     // 0x60: sd t9,184(sp)
762344779Sdim      0xffbe00c0,                     // 0x64: sd fp,192(sp)
763344779Sdim      0xffbf00c8,                     // 0x68: sd ra,200(sp)
764344779Sdim
765344779Sdim      // Callback manager addr.
766344779Sdim      0x00000000,                     // 0x6c: lui $a0,heighest(callbackmgr)
767344779Sdim      0x00000000,                     // 0x70: daddiu $a0,$a0,heigher(callbackmgr)
768344779Sdim      0x00000000,                     // 0x74: dsll $a0,$a0,16
769344779Sdim      0x00000000,                     // 0x78: daddiu $a0,$a0,hi(callbackmgr)
770344779Sdim      0x00000000,                     // 0x7c: dsll $a0,$a0,16
771344779Sdim      0x00000000,                     // 0x80: daddiu $a0,$a0,lo(callbackmgr)
772344779Sdim
773344779Sdim      0x03e02825,                     // 0x84: move $a1, $ra
774344779Sdim      0x64a5ffdc,                     // 0x88: daddiu $a1,$a1,-36
775344779Sdim
776344779Sdim      // JIT re-entry fn addr:
777344779Sdim      0x00000000,                     // 0x8c: lui $t9,reentry
778344779Sdim      0x00000000,                     // 0x90: daddiu $t9,$t9,reentry
779344779Sdim      0x00000000,                     // 0x94: dsll $t9,$t9,
780344779Sdim      0x00000000,                     // 0x98: daddiu $t9,$t9,
781344779Sdim      0x00000000,                     // 0x9c: dsll $t9,$t9,
782344779Sdim      0x00000000,                     // 0xa0: daddiu $t9,$t9,
783344779Sdim      0x0320f809,                     // 0xa4: jalr $t9
784344779Sdim      0x00000000,                     // 0xa8: nop
785344779Sdim      0xdfbf00c8,                     // 0xac: ld ra, 200(sp)
786344779Sdim      0xdfbe00c0,                     // 0xb0: ld fp, 192(sp)
787344779Sdim      0xdfb900b8,                     // 0xb4: ld t9, 184(sp)
788344779Sdim      0xdfb800b0,                     // 0xb8: ld t8, 176(sp)
789344779Sdim      0xdfb700a8,                     // 0xbc: ld s7, 168(sp)
790344779Sdim      0xdfb600a0,                     // 0xc0: ld s6, 160(sp)
791344779Sdim      0xdfb50098,                     // 0xc4: ld s5, 152(sp)
792344779Sdim      0xdfb40090,                     // 0xc8: ld s4, 144(sp)
793344779Sdim      0xdfb30088,                     // 0xcc: ld s3, 136(sp)
794344779Sdim      0xdfb20080,                     // 0xd0: ld s2, 128(sp)
795344779Sdim      0xdfb10078,                     // 0xd4: ld s1, 120(sp)
796344779Sdim      0xdfb00070,                     // 0xd8: ld s0, 112(sp)
797344779Sdim      0xdfaf0068,                     // 0xdc: ld t3, 104(sp)
798344779Sdim      0xdfae0060,                     // 0xe0: ld t2, 96(sp)
799344779Sdim      0xdfad0058,                     // 0xe4: ld t1, 88(sp)
800344779Sdim      0xdfac0050,                     // 0xe8: ld t0, 80(sp)
801344779Sdim      0xdfab0048,                     // 0xec: ld a7, 72(sp)
802344779Sdim      0xdfaa0040,                     // 0xf0: ld a6, 64(sp)
803344779Sdim      0xdfa90038,                     // 0xf4: ld a5, 56(sp)
804344779Sdim      0xdfa80030,                     // 0xf8: ld a4, 48(sp)
805344779Sdim      0xdfa70028,                     // 0xfc: ld a3, 40(sp)
806344779Sdim      0xdfa60020,                     // 0x100: ld a2, 32(sp)
807344779Sdim      0xdfa50018,                     // 0x104: ld a1, 24(sp)
808344779Sdim      0xdfa40010,                     // 0x108: ld a0, 16(sp)
809344779Sdim      0xdfa30008,                     // 0x10c: ld v1, 8(sp)
810344779Sdim      0x67bd00d0,                     // 0x110: daddiu $sp,$sp,208
811344779Sdim      0x0300f825,                     // 0x114: move $ra, $t8
812344779Sdim      0x03200008,                     // 0x118: jr $t9
813344779Sdim      0x0040c825,                     // 0x11c: move $t9, $v0
814344779Sdim  };
815344779Sdim
816344779Sdim  const unsigned ReentryFnAddrOffset = 0x8c;   // JIT re-entry fn addr lui
817344779Sdim  const unsigned CallbackMgrAddrOffset = 0x6c; // Callback manager addr lui
818344779Sdim
819344779Sdim  memcpy(ResolverMem, ResolverCode, sizeof(ResolverCode));
820344779Sdim
821344779Sdim  uint64_t CallMgrAddr = reinterpret_cast<uint64_t>(CallbackMgr);
822344779Sdim
823344779Sdim  uint32_t CallMgrLUi =
824344779Sdim      0x3c040000 | (((CallMgrAddr + 0x800080008000) >> 48) & 0xFFFF);
825344779Sdim  uint32_t CallMgrDADDiu =
826344779Sdim      0x64840000 | (((CallMgrAddr + 0x80008000) >> 32) & 0xFFFF);
827344779Sdim  uint32_t CallMgrDSLL = 0x00042438;
828344779Sdim  uint32_t CallMgrDADDiu2 =
829344779Sdim      0x64840000 | ((((CallMgrAddr + 0x8000) >> 16) & 0xFFFF));
830344779Sdim  uint32_t CallMgrDSLL2 = 0x00042438;
831344779Sdim  uint32_t CallMgrDADDiu3 = 0x64840000 | ((CallMgrAddr)&0xFFFF);
832344779Sdim
833344779Sdim  memcpy(ResolverMem + CallbackMgrAddrOffset, &CallMgrLUi, sizeof(CallMgrLUi));
834344779Sdim  memcpy(ResolverMem + (CallbackMgrAddrOffset + 4), &CallMgrDADDiu,
835344779Sdim         sizeof(CallMgrDADDiu));
836344779Sdim  memcpy(ResolverMem + (CallbackMgrAddrOffset + 8), &CallMgrDSLL,
837344779Sdim         sizeof(CallMgrDSLL));
838344779Sdim  memcpy(ResolverMem + (CallbackMgrAddrOffset + 12), &CallMgrDADDiu2,
839344779Sdim         sizeof(CallMgrDADDiu2));
840344779Sdim  memcpy(ResolverMem + (CallbackMgrAddrOffset + 16), &CallMgrDSLL2,
841344779Sdim         sizeof(CallMgrDSLL2));
842344779Sdim  memcpy(ResolverMem + (CallbackMgrAddrOffset + 20), &CallMgrDADDiu3,
843344779Sdim         sizeof(CallMgrDADDiu3));
844344779Sdim
845344779Sdim  uint64_t ReentryAddr = reinterpret_cast<uint64_t>(ReentryFn);
846344779Sdim
847344779Sdim  uint32_t ReentryLUi =
848344779Sdim      0x3c190000 | (((ReentryAddr + 0x800080008000) >> 48) & 0xFFFF);
849344779Sdim
850344779Sdim  uint32_t ReentryDADDiu =
851344779Sdim      0x67390000 | (((ReentryAddr + 0x80008000) >> 32) & 0xFFFF);
852344779Sdim
853344779Sdim  uint32_t ReentryDSLL = 0x0019cc38;
854344779Sdim
855344779Sdim  uint32_t ReentryDADDiu2 =
856344779Sdim      0x67390000 | (((ReentryAddr + 0x8000) >> 16) & 0xFFFF);
857344779Sdim
858344779Sdim  uint32_t ReentryDSLL2 = 0x0019cc38;
859344779Sdim
860344779Sdim  uint32_t ReentryDADDiu3 = 0x67390000 | ((ReentryAddr)&0xFFFF);
861344779Sdim
862344779Sdim  memcpy(ResolverMem + ReentryFnAddrOffset, &ReentryLUi, sizeof(ReentryLUi));
863344779Sdim  memcpy(ResolverMem + (ReentryFnAddrOffset + 4), &ReentryDADDiu,
864344779Sdim         sizeof(ReentryDADDiu));
865344779Sdim  memcpy(ResolverMem + (ReentryFnAddrOffset + 8), &ReentryDSLL,
866344779Sdim         sizeof(ReentryDSLL));
867344779Sdim  memcpy(ResolverMem + (ReentryFnAddrOffset + 12), &ReentryDADDiu2,
868344779Sdim         sizeof(ReentryDADDiu2));
869344779Sdim  memcpy(ResolverMem + (ReentryFnAddrOffset + 16), &ReentryDSLL2,
870344779Sdim         sizeof(ReentryDSLL2));
871344779Sdim  memcpy(ResolverMem + (ReentryFnAddrOffset + 20), &ReentryDADDiu3,
872344779Sdim         sizeof(ReentryDADDiu3));
873344779Sdim}
874344779Sdim
875344779Sdimvoid OrcMips64::writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
876344779Sdim                                 unsigned NumTrampolines) {
877344779Sdim
878344779Sdim  uint32_t *Trampolines = reinterpret_cast<uint32_t *>(TrampolineMem);
879344779Sdim  uint64_t ResolveAddr = reinterpret_cast<uint64_t>(ResolverAddr);
880344779Sdim
881344779Sdim  uint64_t HeighestAddr = ((ResolveAddr + 0x800080008000) >> 48);
882344779Sdim  uint64_t HeigherAddr = ((ResolveAddr + 0x80008000) >> 32);
883344779Sdim  uint64_t HiAddr = ((ResolveAddr + 0x8000) >> 16);
884344779Sdim
885344779Sdim  for (unsigned I = 0; I < NumTrampolines; ++I) {
886344779Sdim    Trampolines[10 * I + 0] = 0x03e0c025;                            // move $t8,$ra
887344779Sdim    Trampolines[10 * I + 1] = 0x3c190000 | (HeighestAddr & 0xFFFF);  // lui $t9,resolveAddr
888344779Sdim    Trampolines[10 * I + 2] = 0x67390000 | (HeigherAddr & 0xFFFF);   // daddiu $t9,$t9,%higher(resolveAddr)
889344779Sdim    Trampolines[10 * I + 3] = 0x0019cc38;                            // dsll $t9,$t9,16
890344779Sdim    Trampolines[10 * I + 4] = 0x67390000 | (HiAddr & 0xFFFF);        // daddiu $t9,$t9,%hi(ptr)
891344779Sdim    Trampolines[10 * I + 5] = 0x0019cc38;                            // dsll $t9,$t9,16
892344779Sdim    Trampolines[10 * I + 6] = 0x67390000 | (ResolveAddr & 0xFFFF);   // daddiu $t9,$t9,%lo(ptr)
893344779Sdim    Trampolines[10 * I + 7] = 0x0320f809;                            // jalr $t9
894344779Sdim    Trampolines[10 * I + 8] = 0x00000000;                            // nop
895344779Sdim    Trampolines[10 * I + 9] = 0x00000000;                            // nop
896344779Sdim  }
897344779Sdim}
898344779Sdim
899344779SdimError OrcMips64::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
900344779Sdim                                        unsigned MinStubs,
901344779Sdim                                        void *InitialPtrVal) {
902344779Sdim  // Stub format is:
903344779Sdim  //
904344779Sdim  // .section __orc_stubs
905344779Sdim  // stub1:
906344779Sdim  //                 lui $t9,ptr1
907344779Sdim  //                 dsll $t9,$t9,16
908344779Sdim  //                 daddiu $t9,$t9,%hi(ptr)
909344779Sdim  //                 dsll $t9,$t9,16
910344779Sdim  //                 ld $t9,%lo(ptr)
911344779Sdim  //                 jr $t9
912344779Sdim  // stub2:
913344779Sdim  //                 lui $t9,ptr1
914344779Sdim  //                 dsll $t9,$t9,16
915344779Sdim  //                 daddiu $t9,$t9,%hi(ptr)
916344779Sdim  //                 dsll $t9,$t9,16
917344779Sdim  //                 ld $t9,%lo(ptr)
918344779Sdim  //                 jr $t9
919344779Sdim  //
920344779Sdim  // ...
921344779Sdim  //
922344779Sdim  // .section __orc_ptrs
923344779Sdim  // ptr1:
924344779Sdim  //                 .dword 0x0
925344779Sdim  // ptr2:
926344779Sdim  //                 .dword 0x0
927344779Sdim  //
928344779Sdim  // ...
929344779Sdim  const unsigned StubSize = IndirectStubsInfo::StubSize;
930344779Sdim
931344779Sdim  // Emit at least MinStubs, rounded up to fill the pages allocated.
932353358Sdim  static const unsigned PageSize = sys::Process::getPageSizeEstimate();
933344779Sdim  unsigned NumPages = ((MinStubs * StubSize) + (PageSize - 1)) / PageSize;
934344779Sdim  unsigned NumStubs = (NumPages * PageSize) / StubSize;
935344779Sdim
936344779Sdim  // Allocate memory for stubs and pointers in one call.
937344779Sdim  std::error_code EC;
938344779Sdim  auto StubsMem = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
939344779Sdim      2 * NumPages * PageSize, nullptr,
940344779Sdim      sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
941344779Sdim
942344779Sdim  if (EC)
943344779Sdim    return errorCodeToError(EC);
944344779Sdim
945344779Sdim  // Create separate MemoryBlocks representing the stubs and pointers.
946344779Sdim  sys::MemoryBlock StubsBlock(StubsMem.base(), NumPages * PageSize);
947344779Sdim  sys::MemoryBlock PtrsBlock(static_cast<char *>(StubsMem.base()) +
948344779Sdim                                 NumPages * PageSize,
949344779Sdim                             NumPages * PageSize);
950344779Sdim
951344779Sdim  // Populate the stubs page stubs and mark it executable.
952344779Sdim  uint32_t *Stub = reinterpret_cast<uint32_t *>(StubsBlock.base());
953344779Sdim  uint64_t PtrAddr = reinterpret_cast<uint64_t>(PtrsBlock.base());
954344779Sdim
955344779Sdim  for (unsigned I = 0; I < NumStubs; ++I, PtrAddr += 8) {
956344779Sdim    uint64_t HeighestAddr = ((PtrAddr + 0x800080008000) >> 48);
957344779Sdim    uint64_t HeigherAddr = ((PtrAddr + 0x80008000) >> 32);
958344779Sdim    uint64_t HiAddr = ((PtrAddr + 0x8000) >> 16);
959344779Sdim    Stub[8 * I + 0] = 0x3c190000 | (HeighestAddr & 0xFFFF);  // lui $t9,ptr1
960344779Sdim    Stub[8 * I + 1] = 0x67390000 | (HeigherAddr & 0xFFFF);   // daddiu $t9,$t9,%higher(ptr)
961344779Sdim    Stub[8 * I + 2] = 0x0019cc38;                            // dsll $t9,$t9,16
962344779Sdim    Stub[8 * I + 3] = 0x67390000 | (HiAddr & 0xFFFF);        // daddiu $t9,$t9,%hi(ptr)
963344779Sdim    Stub[8 * I + 4] = 0x0019cc38;                            // dsll $t9,$t9,16
964344779Sdim    Stub[8 * I + 5] = 0xdf390000 | (PtrAddr & 0xFFFF);       // ld $t9,%lo(ptr)
965344779Sdim    Stub[8 * I + 6] = 0x03200008;                            // jr $t9
966344779Sdim    Stub[8 * I + 7] = 0x00000000;                            // nop
967344779Sdim  }
968344779Sdim
969344779Sdim  if (auto EC = sys::Memory::protectMappedMemory(
970344779Sdim          StubsBlock, sys::Memory::MF_READ | sys::Memory::MF_EXEC))
971344779Sdim    return errorCodeToError(EC);
972344779Sdim
973344779Sdim  // Initialize all pointers to point at FailureAddress.
974344779Sdim  void **Ptr = reinterpret_cast<void **>(PtrsBlock.base());
975344779Sdim  for (unsigned I = 0; I < NumStubs; ++I)
976344779Sdim    Ptr[I] = InitialPtrVal;
977344779Sdim
978344779Sdim  StubsInfo = IndirectStubsInfo(NumStubs, std::move(StubsMem));
979344779Sdim
980344779Sdim  return Error::success();
981344779Sdim}
982303231Sdim} // End namespace orc.
983303231Sdim} // End namespace llvm.
984