blob: 06c2a8c42f6510e1836cf66d3601b5b493af08b5 [file] [log] [blame]
Lang Hames70b24062016-01-11 00:56:15 +00001//===------ OrcArchSupport.cpp - Architecture specific support code -------===//
Lang Hames4df7ba72015-10-26 06:40:28 +00002//
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
Lang Hames93de2a12015-01-23 21:25:00 +000010#include "llvm/ADT/Triple.h"
Lang Hames70b24062016-01-11 00:56:15 +000011#include "llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h"
Lang Hames98c2ac12015-10-19 17:43:51 +000012#include "llvm/Support/Process.h"
Lang Hames93de2a12015-01-23 21:25:00 +000013#include <array>
14
Lang Hames93de2a12015-01-23 21:25:00 +000015namespace llvm {
Lang Hamese7380612015-02-21 20:44:36 +000016namespace orc {
Lang Hames93de2a12015-01-23 21:25:00 +000017
Rafael Espindolae63e0182015-11-03 16:40:37 +000018void OrcX86_64::writeResolverCode(uint8_t *ResolverMem, JITReentryFn ReentryFn,
19 void *CallbackMgr) {
Lang Hames93de2a12015-01-23 21:25:00 +000020
Rafael Espindolae63e0182015-11-03 16:40:37 +000021 const uint8_t ResolverCode[] = {
22 // resolver_entry:
23 0x55, // 0x00: pushq %rbp
24 0x48, 0x89, 0xe5, // 0x01: movq %rsp, %rbp
25 0x50, // 0x04: pushq %rax
26 0x53, // 0x05: pushq %rbx
27 0x51, // 0x06: pushq %rcx
28 0x52, // 0x07: pushq %rdx
29 0x56, // 0x08: pushq %rsi
30 0x57, // 0x09: pushq %rdi
31 0x41, 0x50, // 0x0a: pushq %r8
32 0x41, 0x51, // 0x0c: pushq %r9
33 0x41, 0x52, // 0x0e: pushq %r10
34 0x41, 0x53, // 0x10: pushq %r11
35 0x41, 0x54, // 0x12: pushq %r12
36 0x41, 0x55, // 0x14: pushq %r13
37 0x41, 0x56, // 0x16: pushq %r14
38 0x41, 0x57, // 0x18: pushq %r15
Lang Hamesd677fa82016-02-05 23:27:48 +000039 0x48, 0x81, 0xec, 0x08, 0x02, 0x00, 0x00, // 0x1a: subq 0x208, %rsp
Rafael Espindolae63e0182015-11-03 16:40:37 +000040 0x48, 0x0f, 0xae, 0x04, 0x24, // 0x21: fxsave64 (%rsp)
Lang Hames120a9b42016-02-06 00:55:08 +000041 0x48, 0xbf, // 0x26: movabsq <CBMgr>, %rdi
42
43 // 0x28: Callback manager addr.
44 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
45
Rafael Espindolae63e0182015-11-03 16:40:37 +000046 0x48, 0x8b, 0x75, 0x08, // 0x30: movq 8(%rbp), %rsi
47 0x48, 0x83, 0xee, 0x06, // 0x34: subq $6, %rsi
Lang Hames120a9b42016-02-06 00:55:08 +000048 0x48, 0xb8, // 0x38: movabsq <REntry>, %rax
Lang Hamese51ab6e2015-04-06 03:01:29 +000049
Rafael Espindolae63e0182015-11-03 16:40:37 +000050 // 0x3a: JIT re-entry fn addr:
51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Lang Hamese51ab6e2015-04-06 03:01:29 +000052
Rafael Espindolae63e0182015-11-03 16:40:37 +000053 0xff, 0xd0, // 0x42: callq *%rax
54 0x48, 0x89, 0x45, 0x08, // 0x44: movq %rax, 8(%rbp)
55 0x48, 0x0f, 0xae, 0x0c, 0x24, // 0x48: fxrstor64 (%rsp)
Lang Hamesd677fa82016-02-05 23:27:48 +000056 0x48, 0x81, 0xc4, 0x08, 0x02, 0x00, 0x00, // 0x4d: addq 0x208, %rsp
Rafael Espindolae63e0182015-11-03 16:40:37 +000057 0x41, 0x5f, // 0x54: popq %r15
58 0x41, 0x5e, // 0x56: popq %r14
59 0x41, 0x5d, // 0x58: popq %r13
60 0x41, 0x5c, // 0x5a: popq %r12
61 0x41, 0x5b, // 0x5c: popq %r11
62 0x41, 0x5a, // 0x5e: popq %r10
63 0x41, 0x59, // 0x60: popq %r9
64 0x41, 0x58, // 0x62: popq %r8
65 0x5f, // 0x64: popq %rdi
66 0x5e, // 0x65: popq %rsi
67 0x5a, // 0x66: popq %rdx
68 0x59, // 0x67: popq %rcx
69 0x5b, // 0x68: popq %rbx
70 0x58, // 0x69: popq %rax
71 0x5d, // 0x6a: popq %rbp
72 0xc3, // 0x6b: retq
Rafael Espindola2f344632015-11-03 16:25:20 +000073 };
74
Rafael Espindolae63e0182015-11-03 16:40:37 +000075 const unsigned ReentryFnAddrOffset = 0x3a;
Lang Hames120a9b42016-02-06 00:55:08 +000076 const unsigned CallbackMgrAddrOffset = 0x28;
Rafael Espindolae63e0182015-11-03 16:40:37 +000077
78 memcpy(ResolverMem, ResolverCode, sizeof(ResolverCode));
79 memcpy(ResolverMem + ReentryFnAddrOffset, &ReentryFn, sizeof(ReentryFn));
80 memcpy(ResolverMem + CallbackMgrAddrOffset, &CallbackMgr,
81 sizeof(CallbackMgr));
82}
Rafael Espindola2f344632015-11-03 16:25:20 +000083
Rafael Espindolae63e0182015-11-03 16:40:37 +000084void OrcX86_64::writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
85 unsigned NumTrampolines) {
Rafael Espindola2f344632015-11-03 16:25:20 +000086
Rafael Espindolae63e0182015-11-03 16:40:37 +000087 unsigned OffsetToPtr = NumTrampolines * TrampolineSize;
88
89 memcpy(TrampolineMem + OffsetToPtr, &ResolverAddr, sizeof(void*));
90
91 uint64_t *Trampolines = reinterpret_cast<uint64_t*>(TrampolineMem);
92 uint64_t CallIndirPCRel = 0xf1c40000000015ff;
93
94 for (unsigned I = 0; I < NumTrampolines; ++I, OffsetToPtr -= TrampolineSize)
95 Trampolines[I] = CallIndirPCRel | ((OffsetToPtr - 6) << 16);
Lang Hames27547142015-02-17 01:18:38 +000096}
97
Lang Hames98c2ac12015-10-19 17:43:51 +000098std::error_code OrcX86_64::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
99 unsigned MinStubs,
100 void *InitialPtrVal) {
101 // Stub format is:
102 //
103 // .section __orc_stubs
104 // stub1:
105 // jmpq *ptr1(%rip)
106 // .byte 0xC4 ; <- Invalid opcode padding.
107 // .byte 0xF1
108 // stub2:
109 // jmpq *ptr2(%rip)
110 //
111 // ...
112 //
113 // .section __orc_ptrs
114 // ptr1:
115 // .quad 0x0
116 // ptr2:
117 // .quad 0x0
118 //
119 // ...
120
121 const unsigned StubSize = IndirectStubsInfo::StubSize;
122
123 // Emit at least MinStubs, rounded up to fill the pages allocated.
124 unsigned PageSize = sys::Process::getPageSize();
125 unsigned NumPages = ((MinStubs * StubSize) + (PageSize - 1)) / PageSize;
126 unsigned NumStubs = (NumPages * PageSize) / StubSize;
127
128 // Allocate memory for stubs and pointers in one call.
129 std::error_code EC;
Lang Hames5796eb22015-10-31 00:55:32 +0000130 auto StubsMem =
131 sys::OwningMemoryBlock(
132 sys::Memory::allocateMappedMemory(2 * NumPages * PageSize, nullptr,
133 sys::Memory::MF_READ |
134 sys::Memory::MF_WRITE,
135 EC));
Lang Hames98c2ac12015-10-19 17:43:51 +0000136
137 if (EC)
138 return EC;
139
140 // Create separate MemoryBlocks representing the stubs and pointers.
Lang Hames5796eb22015-10-31 00:55:32 +0000141 sys::MemoryBlock StubsBlock(StubsMem.base(), NumPages * PageSize);
142 sys::MemoryBlock PtrsBlock(static_cast<char*>(StubsMem.base()) +
143 NumPages * PageSize,
Lang Hames98c2ac12015-10-19 17:43:51 +0000144 NumPages * PageSize);
145
146 // Populate the stubs page stubs and mark it executable.
147 uint64_t *Stub = reinterpret_cast<uint64_t*>(StubsBlock.base());
148 uint64_t PtrOffsetField =
149 static_cast<uint64_t>(NumPages * PageSize - 6) << 16;
150 for (unsigned I = 0; I < NumStubs; ++I)
151 Stub[I] = 0xF1C40000000025ff | PtrOffsetField;
152
153 if (auto EC = sys::Memory::protectMappedMemory(StubsBlock,
154 sys::Memory::MF_READ |
155 sys::Memory::MF_EXEC))
156 return EC;
157
158 // Initialize all pointers to point at FailureAddress.
159 void **Ptr = reinterpret_cast<void**>(PtrsBlock.base());
160 for (unsigned I = 0; I < NumStubs; ++I)
161 Ptr[I] = InitialPtrVal;
162
Lang Hamese28b1182016-02-02 19:31:15 +0000163 StubsInfo = IndirectStubsInfo(NumStubs, std::move(StubsMem));
Lang Hames98c2ac12015-10-19 17:43:51 +0000164
165 return std::error_code();
166}
167
Lang Hames4f8194e2016-02-10 01:02:33 +0000168void OrcI386::writeResolverCode(uint8_t *ResolverMem, JITReentryFn ReentryFn,
169 void *CallbackMgr) {
170
171 const uint8_t ResolverCode[] = {
172 // resolver_entry:
173 0x55, // 0x00: pushl %ebp
174 0x89, 0xe5, // 0x01: movl %esp, %ebp
Lang Hamese1fd99c2016-02-21 22:50:26 +0000175 0x54, // 0x03: pushl %esp
176 0x83, 0xe4, 0xf0, // 0x04: andl $-0x10, %esp
177 0x50, // 0x07: pushl %eax
178 0x53, // 0x08: pushl %ebx
179 0x51, // 0x09: pushl %ecx
180 0x52, // 0x0a: pushl %edx
181 0x56, // 0x0b: pushl %esi
182 0x57, // 0x0c: pushl %edi
183 0x81, 0xec, 0x18, 0x02, 0x00, 0x00, // 0x0d: subl $0x218, %esp
184 0x0f, 0xae, 0x44, 0x24, 0x10, // 0x13: fxsave 0x10(%esp)
185 0x8b, 0x75, 0x04, // 0x18: movl 0x4(%ebp), %esi
186 0x83, 0xee, 0x05, // 0x1b: subl $0x5, %esi
187 0x89, 0x74, 0x24, 0x04, // 0x1e: movl %esi, 0x4(%esp)
188 0xc7, 0x04, 0x24, 0x00, 0x00, 0x00, 0x00, // 0x22: movl <cbmgr>, (%esp)
189 0xb8, 0x00, 0x00, 0x00, 0x00, // 0x29: movl <reentry>, %eax
190 0xff, 0xd0, // 0x2e: calll *%eax
191 0x89, 0x45, 0x04, // 0x30: movl %eax, 0x4(%ebp)
192 0x0f, 0xae, 0x4c, 0x24, 0x10, // 0x33: fxrstor 0x10(%esp)
193 0x81, 0xc4, 0x18, 0x02, 0x00, 0x00, // 0x38: addl $0x218, %esp
194 0x5f, // 0x3e: popl %edi
195 0x5e, // 0x3f: popl %esi
196 0x5a, // 0x40: popl %edx
197 0x59, // 0x41: popl %ecx
198 0x5b, // 0x42: popl %ebx
199 0x58, // 0x43: popl %eax
200 0x8b, 0x65, 0xfc, // 0x44: movl -0x4(%ebp), %esp
201 0x5d, // 0x48: popl %ebp
202 0xc3 // 0x49: retl
Lang Hames4f8194e2016-02-10 01:02:33 +0000203 };
204
Lang Hamese1fd99c2016-02-21 22:50:26 +0000205 const unsigned ReentryFnAddrOffset = 0x2a;
206 const unsigned CallbackMgrAddrOffset = 0x25;
Lang Hames4f8194e2016-02-10 01:02:33 +0000207
208 memcpy(ResolverMem, ResolverCode, sizeof(ResolverCode));
209 memcpy(ResolverMem + ReentryFnAddrOffset, &ReentryFn, sizeof(ReentryFn));
210 memcpy(ResolverMem + CallbackMgrAddrOffset, &CallbackMgr,
211 sizeof(CallbackMgr));
212}
213
214void OrcI386::writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
215 unsigned NumTrampolines) {
216
217 uint64_t CallRelImm = 0xF1C4C400000000e8;
218 uint64_t Resolver = reinterpret_cast<uint64_t>(ResolverAddr);
219 uint64_t ResolverRel =
220 Resolver - reinterpret_cast<uint64_t>(TrampolineMem) - 5;
221
222 uint64_t *Trampolines = reinterpret_cast<uint64_t*>(TrampolineMem);
223 for (unsigned I = 0; I < NumTrampolines; ++I, ResolverRel -= TrampolineSize)
224 Trampolines[I] = CallRelImm | (ResolverRel << 8);
225}
226
227std::error_code OrcI386::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
228 unsigned MinStubs,
229 void *InitialPtrVal) {
230 // Stub format is:
231 //
232 // .section __orc_stubs
233 // stub1:
234 // jmpq *ptr1
235 // .byte 0xC4 ; <- Invalid opcode padding.
236 // .byte 0xF1
237 // stub2:
238 // jmpq *ptr2
239 //
240 // ...
241 //
242 // .section __orc_ptrs
243 // ptr1:
244 // .quad 0x0
245 // ptr2:
246 // .quad 0x0
247 //
248 // ...
249
250 const unsigned StubSize = IndirectStubsInfo::StubSize;
251
252 // Emit at least MinStubs, rounded up to fill the pages allocated.
253 unsigned PageSize = sys::Process::getPageSize();
254 unsigned NumPages = ((MinStubs * StubSize) + (PageSize - 1)) / PageSize;
255 unsigned NumStubs = (NumPages * PageSize) / StubSize;
256
257 // Allocate memory for stubs and pointers in one call.
258 std::error_code EC;
259 auto StubsMem =
260 sys::OwningMemoryBlock(
261 sys::Memory::allocateMappedMemory(2 * NumPages * PageSize, nullptr,
262 sys::Memory::MF_READ |
263 sys::Memory::MF_WRITE,
264 EC));
265
266 if (EC)
267 return EC;
268
269 // Create separate MemoryBlocks representing the stubs and pointers.
270 sys::MemoryBlock StubsBlock(StubsMem.base(), NumPages * PageSize);
271 sys::MemoryBlock PtrsBlock(static_cast<char*>(StubsMem.base()) +
272 NumPages * PageSize,
273 NumPages * PageSize);
274
275 // Populate the stubs page stubs and mark it executable.
276 uint64_t *Stub = reinterpret_cast<uint64_t*>(StubsBlock.base());
277 uint64_t PtrAddr = reinterpret_cast<uint64_t>(PtrsBlock.base());
278 for (unsigned I = 0; I < NumStubs; ++I, PtrAddr += 4)
279 Stub[I] = 0xF1C40000000025ff | (PtrAddr << 16);
280
281 if (auto EC = sys::Memory::protectMappedMemory(StubsBlock,
282 sys::Memory::MF_READ |
283 sys::Memory::MF_EXEC))
284 return EC;
285
286 // Initialize all pointers to point at FailureAddress.
287 void **Ptr = reinterpret_cast<void**>(PtrsBlock.base());
288 for (unsigned I = 0; I < NumStubs; ++I)
289 Ptr[I] = InitialPtrVal;
290
291 StubsInfo = IndirectStubsInfo(NumStubs, std::move(StubsMem));
292
293 return std::error_code();
294}
295
Lang Hamese7380612015-02-21 20:44:36 +0000296} // End namespace orc.
297} // End namespace llvm.