blob: 606b5616f59eca4c480e0445aa4999e062014187 [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 Hamese7380612015-02-21 20:44:36 +0000168} // End namespace orc.
169} // End namespace llvm.