1 //===------- OrcTargetSupport.cpp - Target support utilities for Orc ------===//
2 //
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
10 #include "llvm/ADT/Triple.h"
11 #include "llvm/ExecutionEngine/Orc/OrcTargetSupport.h"
12 #include "llvm/Support/Process.h"
13 #include <array>
14
15 namespace llvm {
16 namespace orc {
17
writeResolverCode(uint8_t * ResolverMem,JITReentryFn ReentryFn,void * CallbackMgr)18 void OrcX86_64::writeResolverCode(uint8_t *ResolverMem, JITReentryFn ReentryFn,
19 void *CallbackMgr) {
20
21 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
39 0x48, 0x81, 0xec, 0x08, 0x02, 0x00, 0x00, // 0x1a: subq 20, %rsp
40 0x48, 0x0f, 0xae, 0x04, 0x24, // 0x21: fxsave64 (%rsp)
41 0x48, 0x8d, 0x3d, 0x43, 0x00, 0x00, 0x00, // 0x26: leaq 67(%rip), %rdi
42 0x48, 0x8b, 0x3f, // 0x2d: movq (%rdi), %rdi
43 0x48, 0x8b, 0x75, 0x08, // 0x30: movq 8(%rbp), %rsi
44 0x48, 0x83, 0xee, 0x06, // 0x34: subq $6, %rsi
45 0x48, 0xb8, // 0x38: movabsq $0, %rax
46
47 // 0x3a: JIT re-entry fn addr:
48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49
50 0xff, 0xd0, // 0x42: callq *%rax
51 0x48, 0x89, 0x45, 0x08, // 0x44: movq %rax, 8(%rbp)
52 0x48, 0x0f, 0xae, 0x0c, 0x24, // 0x48: fxrstor64 (%rsp)
53 0x48, 0x81, 0xc4, 0x08, 0x02, 0x00, 0x00, // 0x4d: addq 20, %rsp
54 0x41, 0x5f, // 0x54: popq %r15
55 0x41, 0x5e, // 0x56: popq %r14
56 0x41, 0x5d, // 0x58: popq %r13
57 0x41, 0x5c, // 0x5a: popq %r12
58 0x41, 0x5b, // 0x5c: popq %r11
59 0x41, 0x5a, // 0x5e: popq %r10
60 0x41, 0x59, // 0x60: popq %r9
61 0x41, 0x58, // 0x62: popq %r8
62 0x5f, // 0x64: popq %rdi
63 0x5e, // 0x65: popq %rsi
64 0x5a, // 0x66: popq %rdx
65 0x59, // 0x67: popq %rcx
66 0x5b, // 0x68: popq %rbx
67 0x58, // 0x69: popq %rax
68 0x5d, // 0x6a: popq %rbp
69 0xc3, // 0x6b: retq
70 0x00, 0x00, 0x00, 0x00, // 0x6c: <padding>
71
72 // 0x70: Callback mgr address.
73 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
74 };
75
76 const unsigned ReentryFnAddrOffset = 0x3a;
77 const unsigned CallbackMgrAddrOffset = 0x70;
78
79 memcpy(ResolverMem, ResolverCode, sizeof(ResolverCode));
80 memcpy(ResolverMem + ReentryFnAddrOffset, &ReentryFn, sizeof(ReentryFn));
81 memcpy(ResolverMem + CallbackMgrAddrOffset, &CallbackMgr,
82 sizeof(CallbackMgr));
83 }
84
writeTrampolines(uint8_t * TrampolineMem,void * ResolverAddr,unsigned NumTrampolines)85 void OrcX86_64::writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
86 unsigned NumTrampolines) {
87
88 unsigned OffsetToPtr = NumTrampolines * TrampolineSize;
89
90 memcpy(TrampolineMem + OffsetToPtr, &ResolverAddr, sizeof(void*));
91
92 uint64_t *Trampolines = reinterpret_cast<uint64_t*>(TrampolineMem);
93 uint64_t CallIndirPCRel = 0xf1c40000000015ff;
94
95 for (unsigned I = 0; I < NumTrampolines; ++I, OffsetToPtr -= TrampolineSize)
96 Trampolines[I] = CallIndirPCRel | ((OffsetToPtr - 6) << 16);
97 }
98
emitIndirectStubsBlock(IndirectStubsInfo & StubsInfo,unsigned MinStubs,void * InitialPtrVal)99 std::error_code OrcX86_64::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
100 unsigned MinStubs,
101 void *InitialPtrVal) {
102 // Stub format is:
103 //
104 // .section __orc_stubs
105 // stub1:
106 // jmpq *ptr1(%rip)
107 // .byte 0xC4 ; <- Invalid opcode padding.
108 // .byte 0xF1
109 // stub2:
110 // jmpq *ptr2(%rip)
111 //
112 // ...
113 //
114 // .section __orc_ptrs
115 // ptr1:
116 // .quad 0x0
117 // ptr2:
118 // .quad 0x0
119 //
120 // ...
121
122 const unsigned StubSize = IndirectStubsInfo::StubSize;
123
124 // Emit at least MinStubs, rounded up to fill the pages allocated.
125 unsigned PageSize = sys::Process::getPageSize();
126 unsigned NumPages = ((MinStubs * StubSize) + (PageSize - 1)) / PageSize;
127 unsigned NumStubs = (NumPages * PageSize) / StubSize;
128
129 // Allocate memory for stubs and pointers in one call.
130 std::error_code EC;
131 auto StubsMem =
132 sys::OwningMemoryBlock(
133 sys::Memory::allocateMappedMemory(2 * NumPages * PageSize, nullptr,
134 sys::Memory::MF_READ |
135 sys::Memory::MF_WRITE,
136 EC));
137
138 if (EC)
139 return EC;
140
141 // Create separate MemoryBlocks representing the stubs and pointers.
142 sys::MemoryBlock StubsBlock(StubsMem.base(), NumPages * PageSize);
143 sys::MemoryBlock PtrsBlock(static_cast<char*>(StubsMem.base()) +
144 NumPages * PageSize,
145 NumPages * PageSize);
146
147 // Populate the stubs page stubs and mark it executable.
148 uint64_t *Stub = reinterpret_cast<uint64_t*>(StubsBlock.base());
149 uint64_t PtrOffsetField =
150 static_cast<uint64_t>(NumPages * PageSize - 6) << 16;
151 for (unsigned I = 0; I < NumStubs; ++I)
152 Stub[I] = 0xF1C40000000025ff | PtrOffsetField;
153
154 if (auto EC = sys::Memory::protectMappedMemory(StubsBlock,
155 sys::Memory::MF_READ |
156 sys::Memory::MF_EXEC))
157 return EC;
158
159 // Initialize all pointers to point at FailureAddress.
160 void **Ptr = reinterpret_cast<void**>(PtrsBlock.base());
161 for (unsigned I = 0; I < NumStubs; ++I)
162 Ptr[I] = InitialPtrVal;
163
164 StubsInfo.NumStubs = NumStubs;
165 StubsInfo.StubsMem = std::move(StubsMem);
166
167 return std::error_code();
168 }
169
170 } // End namespace orc.
171 } // End namespace llvm.
172