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