blob: b51e3cd002d2f5a07d37e0e99cdcf098c3fa377e [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 Hames70b24062016-01-11 00:56:15 +000010#include "llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h"
Lang Hames1fa0e0e2016-04-25 21:21:20 +000011#include "llvm/ADT/Triple.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[] = {
Lang Hames1fa0e0e2016-04-25 21:21:20 +000021 // 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
38 0x48, 0x81, 0xec, 0x08, 0x02, 0x00, 0x00, // 0x1a: subq 0x208, %rsp
39 0x48, 0x0f, 0xae, 0x04, 0x24, // 0x21: fxsave64 (%rsp)
40 0x48, 0xbf, // 0x26: movabsq <CBMgr>, %rdi
Lang Hames120a9b42016-02-06 00:55:08 +000041
Lang Hames1fa0e0e2016-04-25 21:21:20 +000042 // 0x28: Callback manager addr.
43 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Lang Hames120a9b42016-02-06 00:55:08 +000044
Lang Hames1fa0e0e2016-04-25 21:21:20 +000045 0x48, 0x8b, 0x75, 0x08, // 0x30: movq 8(%rbp), %rsi
46 0x48, 0x83, 0xee, 0x06, // 0x34: subq $6, %rsi
47 0x48, 0xb8, // 0x38: movabsq <REntry>, %rax
Lang Hamese51ab6e2015-04-06 03:01:29 +000048
Lang Hames1fa0e0e2016-04-25 21:21:20 +000049 // 0x3a: JIT re-entry fn addr:
50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Lang Hamese51ab6e2015-04-06 03:01:29 +000051
Lang Hames1fa0e0e2016-04-25 21:21:20 +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)
55 0x48, 0x81, 0xc4, 0x08, 0x02, 0x00, 0x00, // 0x4d: addq 0x208, %rsp
56 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;
Lang Hames1fa0e0e2016-04-25 21:21:20 +000076
Rafael Espindolae63e0182015-11-03 16:40:37 +000077 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,
Lang Hames1fa0e0e2016-04-25 21:21:20 +000084 unsigned NumTrampolines) {
Rafael Espindola2f344632015-11-03 16:25:20 +000085
Rafael Espindolae63e0182015-11-03 16:40:37 +000086 unsigned OffsetToPtr = NumTrampolines * TrampolineSize;
87
Lang Hames1fa0e0e2016-04-25 21:21:20 +000088 memcpy(TrampolineMem + OffsetToPtr, &ResolverAddr, sizeof(void *));
Rafael Espindolae63e0182015-11-03 16:40:37 +000089
Lang Hames1fa0e0e2016-04-25 21:21:20 +000090 uint64_t *Trampolines = reinterpret_cast<uint64_t *>(TrampolineMem);
Rafael Espindolae63e0182015-11-03 16:40:37 +000091 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 Hamesef5a0ee2016-04-25 19:56:45 +000097Error OrcX86_64::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
98 unsigned MinStubs,
99 void *InitialPtrVal) {
Lang Hames98c2ac12015-10-19 17:43:51 +0000100 // 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 Hames1fa0e0e2016-04-25 21:21:20 +0000129 auto StubsMem = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
130 2 * NumPages * PageSize, nullptr,
131 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
Lang Hames98c2ac12015-10-19 17:43:51 +0000132
133 if (EC)
Lang Hamesef5a0ee2016-04-25 19:56:45 +0000134 return errorCodeToError(EC);
Lang Hames98c2ac12015-10-19 17:43:51 +0000135
136 // Create separate MemoryBlocks representing the stubs and pointers.
Lang Hames5796eb22015-10-31 00:55:32 +0000137 sys::MemoryBlock StubsBlock(StubsMem.base(), NumPages * PageSize);
Lang Hames1fa0e0e2016-04-25 21:21:20 +0000138 sys::MemoryBlock PtrsBlock(static_cast<char *>(StubsMem.base()) +
139 NumPages * PageSize,
Lang Hames98c2ac12015-10-19 17:43:51 +0000140 NumPages * PageSize);
141
142 // Populate the stubs page stubs and mark it executable.
Lang Hames1fa0e0e2016-04-25 21:21:20 +0000143 uint64_t *Stub = reinterpret_cast<uint64_t *>(StubsBlock.base());
144 uint64_t PtrOffsetField = static_cast<uint64_t>(NumPages * PageSize - 6)
145 << 16;
Lang Hames98c2ac12015-10-19 17:43:51 +0000146 for (unsigned I = 0; I < NumStubs; ++I)
147 Stub[I] = 0xF1C40000000025ff | PtrOffsetField;
148
Lang Hames1fa0e0e2016-04-25 21:21:20 +0000149 if (auto EC = sys::Memory::protectMappedMemory(
150 StubsBlock, sys::Memory::MF_READ | sys::Memory::MF_EXEC))
Lang Hamesef5a0ee2016-04-25 19:56:45 +0000151 return errorCodeToError(EC);
Lang Hames98c2ac12015-10-19 17:43:51 +0000152
153 // Initialize all pointers to point at FailureAddress.
Lang Hames1fa0e0e2016-04-25 21:21:20 +0000154 void **Ptr = reinterpret_cast<void **>(PtrsBlock.base());
Lang Hames98c2ac12015-10-19 17:43:51 +0000155 for (unsigned I = 0; I < NumStubs; ++I)
156 Ptr[I] = InitialPtrVal;
157
Lang Hamese28b1182016-02-02 19:31:15 +0000158 StubsInfo = IndirectStubsInfo(NumStubs, std::move(StubsMem));
Lang Hames98c2ac12015-10-19 17:43:51 +0000159
Lang Hamesef5a0ee2016-04-25 19:56:45 +0000160 return Error::success();
Lang Hames98c2ac12015-10-19 17:43:51 +0000161}
162
Lang Hames4f8194e2016-02-10 01:02:33 +0000163void OrcI386::writeResolverCode(uint8_t *ResolverMem, JITReentryFn ReentryFn,
164 void *CallbackMgr) {
165
166 const uint8_t ResolverCode[] = {
Lang Hames1fa0e0e2016-04-25 21:21:20 +0000167 // resolver_entry:
168 0x55, // 0x00: pushl %ebp
169 0x89, 0xe5, // 0x01: movl %esp, %ebp
170 0x54, // 0x03: pushl %esp
171 0x83, 0xe4, 0xf0, // 0x04: andl $-0x10, %esp
172 0x50, // 0x07: pushl %eax
173 0x53, // 0x08: pushl %ebx
174 0x51, // 0x09: pushl %ecx
175 0x52, // 0x0a: pushl %edx
176 0x56, // 0x0b: pushl %esi
177 0x57, // 0x0c: pushl %edi
178 0x81, 0xec, 0x18, 0x02, 0x00, 0x00, // 0x0d: subl $0x218, %esp
179 0x0f, 0xae, 0x44, 0x24, 0x10, // 0x13: fxsave 0x10(%esp)
180 0x8b, 0x75, 0x04, // 0x18: movl 0x4(%ebp), %esi
181 0x83, 0xee, 0x05, // 0x1b: subl $0x5, %esi
182 0x89, 0x74, 0x24, 0x04, // 0x1e: movl %esi, 0x4(%esp)
183 0xc7, 0x04, 0x24, 0x00, 0x00, 0x00,
184 0x00, // 0x22: movl <cbmgr>, (%esp)
185 0xb8, 0x00, 0x00, 0x00, 0x00, // 0x29: movl <reentry>, %eax
186 0xff, 0xd0, // 0x2e: calll *%eax
187 0x89, 0x45, 0x04, // 0x30: movl %eax, 0x4(%ebp)
188 0x0f, 0xae, 0x4c, 0x24, 0x10, // 0x33: fxrstor 0x10(%esp)
189 0x81, 0xc4, 0x18, 0x02, 0x00, 0x00, // 0x38: addl $0x218, %esp
190 0x5f, // 0x3e: popl %edi
191 0x5e, // 0x3f: popl %esi
192 0x5a, // 0x40: popl %edx
193 0x59, // 0x41: popl %ecx
194 0x5b, // 0x42: popl %ebx
195 0x58, // 0x43: popl %eax
196 0x8b, 0x65, 0xfc, // 0x44: movl -0x4(%ebp), %esp
197 0x5d, // 0x48: popl %ebp
198 0xc3 // 0x49: retl
Lang Hames4f8194e2016-02-10 01:02:33 +0000199 };
200
Lang Hamese1fd99c2016-02-21 22:50:26 +0000201 const unsigned ReentryFnAddrOffset = 0x2a;
202 const unsigned CallbackMgrAddrOffset = 0x25;
Lang Hames4f8194e2016-02-10 01:02:33 +0000203
204 memcpy(ResolverMem, ResolverCode, sizeof(ResolverCode));
205 memcpy(ResolverMem + ReentryFnAddrOffset, &ReentryFn, sizeof(ReentryFn));
206 memcpy(ResolverMem + CallbackMgrAddrOffset, &CallbackMgr,
207 sizeof(CallbackMgr));
208}
209
210void OrcI386::writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
211 unsigned NumTrampolines) {
212
213 uint64_t CallRelImm = 0xF1C4C400000000e8;
214 uint64_t Resolver = reinterpret_cast<uint64_t>(ResolverAddr);
215 uint64_t ResolverRel =
Lang Hames1fa0e0e2016-04-25 21:21:20 +0000216 Resolver - reinterpret_cast<uint64_t>(TrampolineMem) - 5;
Lang Hames4f8194e2016-02-10 01:02:33 +0000217
Lang Hames1fa0e0e2016-04-25 21:21:20 +0000218 uint64_t *Trampolines = reinterpret_cast<uint64_t *>(TrampolineMem);
Lang Hames4f8194e2016-02-10 01:02:33 +0000219 for (unsigned I = 0; I < NumTrampolines; ++I, ResolverRel -= TrampolineSize)
220 Trampolines[I] = CallRelImm | (ResolverRel << 8);
221}
222
Lang Hamesef5a0ee2016-04-25 19:56:45 +0000223Error OrcI386::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
Lang Hames1fa0e0e2016-04-25 21:21:20 +0000224 unsigned MinStubs, void *InitialPtrVal) {
Lang Hames4f8194e2016-02-10 01:02:33 +0000225 // Stub format is:
226 //
227 // .section __orc_stubs
228 // stub1:
229 // jmpq *ptr1
230 // .byte 0xC4 ; <- Invalid opcode padding.
231 // .byte 0xF1
232 // stub2:
233 // jmpq *ptr2
234 //
235 // ...
236 //
237 // .section __orc_ptrs
238 // ptr1:
239 // .quad 0x0
240 // ptr2:
241 // .quad 0x0
242 //
243 // ...
244
245 const unsigned StubSize = IndirectStubsInfo::StubSize;
246
247 // Emit at least MinStubs, rounded up to fill the pages allocated.
248 unsigned PageSize = sys::Process::getPageSize();
249 unsigned NumPages = ((MinStubs * StubSize) + (PageSize - 1)) / PageSize;
250 unsigned NumStubs = (NumPages * PageSize) / StubSize;
251
252 // Allocate memory for stubs and pointers in one call.
253 std::error_code EC;
Lang Hames1fa0e0e2016-04-25 21:21:20 +0000254 auto StubsMem = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
255 2 * NumPages * PageSize, nullptr,
256 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
Lang Hames4f8194e2016-02-10 01:02:33 +0000257
258 if (EC)
Lang Hamesef5a0ee2016-04-25 19:56:45 +0000259 return errorCodeToError(EC);
Lang Hames4f8194e2016-02-10 01:02:33 +0000260
261 // Create separate MemoryBlocks representing the stubs and pointers.
262 sys::MemoryBlock StubsBlock(StubsMem.base(), NumPages * PageSize);
Lang Hames1fa0e0e2016-04-25 21:21:20 +0000263 sys::MemoryBlock PtrsBlock(static_cast<char *>(StubsMem.base()) +
264 NumPages * PageSize,
Lang Hames4f8194e2016-02-10 01:02:33 +0000265 NumPages * PageSize);
266
267 // Populate the stubs page stubs and mark it executable.
Lang Hames1fa0e0e2016-04-25 21:21:20 +0000268 uint64_t *Stub = reinterpret_cast<uint64_t *>(StubsBlock.base());
Lang Hames4f8194e2016-02-10 01:02:33 +0000269 uint64_t PtrAddr = reinterpret_cast<uint64_t>(PtrsBlock.base());
270 for (unsigned I = 0; I < NumStubs; ++I, PtrAddr += 4)
271 Stub[I] = 0xF1C40000000025ff | (PtrAddr << 16);
272
Lang Hames1fa0e0e2016-04-25 21:21:20 +0000273 if (auto EC = sys::Memory::protectMappedMemory(
274 StubsBlock, sys::Memory::MF_READ | sys::Memory::MF_EXEC))
Lang Hamesef5a0ee2016-04-25 19:56:45 +0000275 return errorCodeToError(EC);
Lang Hames4f8194e2016-02-10 01:02:33 +0000276
277 // Initialize all pointers to point at FailureAddress.
Lang Hames1fa0e0e2016-04-25 21:21:20 +0000278 void **Ptr = reinterpret_cast<void **>(PtrsBlock.base());
Lang Hames4f8194e2016-02-10 01:02:33 +0000279 for (unsigned I = 0; I < NumStubs; ++I)
280 Ptr[I] = InitialPtrVal;
281
282 StubsInfo = IndirectStubsInfo(NumStubs, std::move(StubsMem));
283
Lang Hamesef5a0ee2016-04-25 19:56:45 +0000284 return Error::success();
Lang Hames4f8194e2016-02-10 01:02:33 +0000285}
286
Lang Hamese7380612015-02-21 20:44:36 +0000287} // End namespace orc.
288} // End namespace llvm.