1 | //=== OrcV2CBindingsMemoryManager.c - OrcV2 Memory Manager C Bindings Demo ===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This demo illustrates the C-API bindings for custom memory managers in |
10 | // ORCv2. They are used here to place generated code into manually allocated |
11 | // buffers that are subsequently marked as executable. |
12 | // |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #include "llvm-c/Core.h" |
16 | #include "llvm-c/Error.h" |
17 | #include "llvm-c/LLJIT.h" |
18 | #include "llvm-c/OrcEE.h" |
19 | #include "llvm-c/Support.h" |
20 | #include "llvm-c/Target.h" |
21 | |
22 | #include <assert.h> |
23 | #include <stdio.h> |
24 | #include <stdlib.h> |
25 | |
26 | #if defined(_WIN32) |
27 | #include <windows.h> |
28 | #else |
29 | #include <dlfcn.h> |
30 | #include <sys/mman.h> |
31 | #endif |
32 | |
33 | struct Section { |
34 | void *Ptr; |
35 | size_t Size; |
36 | LLVMBool IsCode; |
37 | }; |
38 | |
39 | char CtxCtxPlaceholder; |
40 | char CtxPlaceholder; |
41 | |
42 | #define MaxSections 16 |
43 | static size_t SectionCount = 0; |
44 | static struct Section Sections[MaxSections]; |
45 | |
46 | void *addSection(size_t Size, LLVMBool IsCode) { |
47 | if (SectionCount >= MaxSections) { |
48 | fprintf(stderr, format: "addSection(): Too many sections!\n" ); |
49 | abort(); |
50 | } |
51 | |
52 | #if defined(_WIN32) |
53 | void *Ptr = |
54 | VirtualAlloc(NULL, Size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); |
55 | if (!Ptr) { |
56 | fprintf(stderr, "addSection(): Memory allocation failed!\n" ); |
57 | abort(); |
58 | } |
59 | #else |
60 | void *Ptr = mmap(NULL, len: Size, PROT_READ | PROT_WRITE, |
61 | MAP_PRIVATE | MAP_ANONYMOUS, fd: -1, offset: 0); |
62 | if (Ptr == MAP_FAILED) { |
63 | fprintf(stderr, format: "addSection(): Memory allocation failed!\n" ); |
64 | abort(); |
65 | } |
66 | #endif |
67 | |
68 | Sections[SectionCount].Ptr = Ptr; |
69 | Sections[SectionCount].Size = Size; |
70 | Sections[SectionCount].IsCode = IsCode; |
71 | SectionCount++; |
72 | return Ptr; |
73 | } |
74 | |
75 | // Callbacks to create the context for the subsequent functions (not used in |
76 | // this example) |
77 | void *memCreateContext(void *CtxCtx) { |
78 | assert(CtxCtx == &CtxCtxPlaceholder && "Unexpected CtxCtx value" ); |
79 | return &CtxPlaceholder; |
80 | } |
81 | |
82 | void memNotifyTerminating(void *CtxCtx) { |
83 | assert(CtxCtx == &CtxCtxPlaceholder && "Unexpected CtxCtx value" ); |
84 | } |
85 | |
86 | uint8_t *memAllocate(void *Opaque, uintptr_t Size, unsigned Align, unsigned Id, |
87 | const char *Name) { |
88 | printf(format: "Allocated code section \"%s\"\n" , Name); |
89 | return addSection(Size, IsCode: 1); |
90 | } |
91 | |
92 | uint8_t *memAllocateData(void *Opaque, uintptr_t Size, unsigned Align, |
93 | unsigned Id, const char *Name, LLVMBool ReadOnly) { |
94 | printf(format: "Allocated data section \"%s\"\n" , Name); |
95 | return addSection(Size, IsCode: 0); |
96 | } |
97 | |
98 | LLVMBool memFinalize(void *Opaque, char **Err) { |
99 | printf(format: "Marking code sections as executable ..\n" ); |
100 | for (size_t i = 0; i < SectionCount; ++i) { |
101 | if (Sections[i].IsCode) { |
102 | LLVMBool fail; |
103 | #if defined(_WIN32) |
104 | DWORD unused; |
105 | fail = VirtualProtect(Sections[i].Ptr, Sections[i].Size, |
106 | PAGE_EXECUTE_READ, &unused) == 0; |
107 | #else |
108 | fail = mprotect(addr: Sections[i].Ptr, len: Sections[i].Size, |
109 | PROT_READ | PROT_EXEC) == -1; |
110 | #endif |
111 | if (fail) { |
112 | fprintf(stderr, format: "Could not mark code section as executable!\n" ); |
113 | abort(); |
114 | } |
115 | } |
116 | } |
117 | return 0; |
118 | } |
119 | |
120 | void memDestroy(void *Opaque) { |
121 | assert(Opaque == &CtxPlaceholder && "Unexpected Ctx value" ); |
122 | printf(format: "Releasing section memory ..\n" ); |
123 | for (size_t i = 0; i < SectionCount; ++i) { |
124 | LLVMBool fail; |
125 | #if defined(_WIN32) |
126 | fail = VirtualFree(Sections[i].Ptr, 0, MEM_RELEASE) == 0; |
127 | #else |
128 | fail = munmap(addr: Sections[i].Ptr, len: Sections[i].Size) == -1; |
129 | #endif |
130 | if (fail) { |
131 | fprintf(stderr, format: "Could not release memory for section!" ); |
132 | abort(); |
133 | } |
134 | } |
135 | } |
136 | |
137 | LLVMOrcObjectLayerRef objectLinkingLayerCreator(void *Opaque, |
138 | LLVMOrcExecutionSessionRef ES, |
139 | const char *Triple) { |
140 | return LLVMOrcCreateRTDyldObjectLinkingLayerWithMCJITMemoryManagerLikeCallbacks( |
141 | ES, CreateContextCtx: &CtxCtxPlaceholder, CreateContext: memCreateContext, NotifyTerminating: memNotifyTerminating, |
142 | AllocateCodeSection: memAllocate, AllocateDataSection: memAllocateData, FinalizeMemory: memFinalize, Destroy: memDestroy); |
143 | } |
144 | |
145 | int handleError(LLVMErrorRef Err) { |
146 | char *ErrMsg = LLVMGetErrorMessage(Err); |
147 | fprintf(stderr, format: "Error: %s\n" , ErrMsg); |
148 | LLVMDisposeErrorMessage(ErrMsg); |
149 | return 1; |
150 | } |
151 | |
152 | LLVMOrcThreadSafeModuleRef createDemoModule(void) { |
153 | // Create a new ThreadSafeContext and underlying LLVMContext. |
154 | LLVMOrcThreadSafeContextRef TSCtx = LLVMOrcCreateNewThreadSafeContext(); |
155 | |
156 | // Get a reference to the underlying LLVMContext. |
157 | LLVMContextRef Ctx = LLVMOrcThreadSafeContextGetContext(TSCtx); |
158 | |
159 | // Create a new LLVM module. |
160 | LLVMModuleRef M = LLVMModuleCreateWithNameInContext(ModuleID: "demo" , C: Ctx); |
161 | |
162 | // Add a "sum" function": |
163 | // - Create the function type and function instance. |
164 | LLVMTypeRef ParamTypes[] = {LLVMInt32Type(), LLVMInt32Type()}; |
165 | LLVMTypeRef SumFunctionType = |
166 | LLVMFunctionType(ReturnType: LLVMInt32Type(), ParamTypes, ParamCount: 2, IsVarArg: 0); |
167 | LLVMValueRef SumFunction = LLVMAddFunction(M, Name: "sum" , FunctionTy: SumFunctionType); |
168 | |
169 | // - Add a basic block to the function. |
170 | LLVMBasicBlockRef EntryBB = LLVMAppendBasicBlock(Fn: SumFunction, Name: "entry" ); |
171 | |
172 | // - Add an IR builder and point it at the end of the basic block. |
173 | LLVMBuilderRef Builder = LLVMCreateBuilder(); |
174 | LLVMPositionBuilderAtEnd(Builder, Block: EntryBB); |
175 | |
176 | // - Get the two function arguments and use them co construct an "add" |
177 | // instruction. |
178 | LLVMValueRef SumArg0 = LLVMGetParam(Fn: SumFunction, Index: 0); |
179 | LLVMValueRef SumArg1 = LLVMGetParam(Fn: SumFunction, Index: 1); |
180 | LLVMValueRef Result = LLVMBuildAdd(Builder, LHS: SumArg0, RHS: SumArg1, Name: "result" ); |
181 | |
182 | // - Build the return instruction. |
183 | LLVMBuildRet(Builder, V: Result); |
184 | |
185 | // Our demo module is now complete. Wrap it and our ThreadSafeContext in a |
186 | // ThreadSafeModule. |
187 | LLVMOrcThreadSafeModuleRef TSM = LLVMOrcCreateNewThreadSafeModule(M, TSCtx); |
188 | |
189 | // Dispose of our local ThreadSafeContext value. The underlying LLVMContext |
190 | // will be kept alive by our ThreadSafeModule, TSM. |
191 | LLVMOrcDisposeThreadSafeContext(TSCtx); |
192 | |
193 | // Return the result. |
194 | return TSM; |
195 | } |
196 | |
197 | int main(int argc, const char *argv[]) { |
198 | |
199 | int MainResult = 0; |
200 | |
201 | // Parse command line arguments and initialize LLVM Core. |
202 | LLVMParseCommandLineOptions(argc, argv, Overview: "" ); |
203 | |
204 | // Initialize native target codegen and asm printer. |
205 | LLVMInitializeNativeTarget(); |
206 | LLVMInitializeNativeAsmPrinter(); |
207 | |
208 | // Create the JIT instance. |
209 | LLVMOrcLLJITRef J; |
210 | { |
211 | LLVMErrorRef Err; |
212 | |
213 | LLVMOrcLLJITBuilderRef Builder = LLVMOrcCreateLLJITBuilder(); |
214 | LLVMOrcLLJITBuilderSetObjectLinkingLayerCreator( |
215 | Builder, F: objectLinkingLayerCreator, NULL); |
216 | |
217 | if ((Err = LLVMOrcCreateLLJIT(Result: &J, Builder))) { |
218 | MainResult = handleError(Err); |
219 | goto llvm_shutdown; |
220 | } |
221 | } |
222 | |
223 | // Create our demo module. |
224 | LLVMOrcThreadSafeModuleRef TSM = createDemoModule(); |
225 | |
226 | // Add our demo module to the JIT. |
227 | { |
228 | LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J); |
229 | LLVMErrorRef Err; |
230 | if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, JD: MainJD, TSM))) { |
231 | // If adding the ThreadSafeModule fails then we need to clean it up |
232 | // ourselves. If adding it succeeds the JIT will manage the memory. |
233 | LLVMOrcDisposeThreadSafeModule(TSM); |
234 | MainResult = handleError(Err); |
235 | goto jit_cleanup; |
236 | } |
237 | } |
238 | |
239 | // Look up the address of our demo entry point. |
240 | LLVMOrcJITTargetAddress SumAddr; |
241 | { |
242 | LLVMErrorRef Err; |
243 | if ((Err = LLVMOrcLLJITLookup(J, Result: &SumAddr, Name: "sum" ))) { |
244 | MainResult = handleError(Err); |
245 | goto jit_cleanup; |
246 | } |
247 | } |
248 | |
249 | // If we made it here then everything succeeded. Execute our JIT'd code. |
250 | int32_t (*Sum)(int32_t, int32_t) = (int32_t(*)(int32_t, int32_t))SumAddr; |
251 | int32_t Result = Sum(1, 2); |
252 | |
253 | // Print the result. |
254 | printf(format: "1 + 2 = %i\n" , Result); |
255 | |
256 | jit_cleanup: |
257 | // Destroy our JIT instance. This will clean up any memory that the JIT has |
258 | // taken ownership of. This operation is non-trivial (e.g. it may need to |
259 | // JIT static destructors) and may also fail. In that case we want to render |
260 | // the error to stderr, but not overwrite any existing return value. |
261 | { |
262 | LLVMErrorRef Err; |
263 | if ((Err = LLVMOrcDisposeLLJIT(J))) { |
264 | int NewFailureResult = handleError(Err); |
265 | if (MainResult == 0) |
266 | MainResult = NewFailureResult; |
267 | } |
268 | } |
269 | |
270 | llvm_shutdown: |
271 | // Shut down LLVM. |
272 | LLVMShutdown(); |
273 | |
274 | return MainResult; |
275 | } |
276 | |