1 //=== OrcV2CBindingsMemoryManager.c - OrcV2 Memory Manager C Bindings Demo ===//
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
7 //===----------------------------------------------------------------------===//
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.
13 //===----------------------------------------------------------------------===//
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"
39 char CtxCtxPlaceholder
;
42 #define MaxSections 16
43 static size_t SectionCount
= 0;
44 static struct Section Sections
[MaxSections
];
46 void *addSection(size_t Size
, LLVMBool IsCode
) {
47 if (SectionCount
>= MaxSections
) {
48 fprintf(stderr
, "addSection(): Too many sections!\n");
54 VirtualAlloc(NULL
, Size
, MEM_RESERVE
| MEM_COMMIT
, PAGE_READWRITE
);
56 fprintf(stderr
, "addSection(): Memory allocation failed!\n");
60 void *Ptr
= mmap(NULL
, Size
, PROT_READ
| PROT_WRITE
,
61 MAP_PRIVATE
| MAP_ANONYMOUS
, -1, 0);
62 if (Ptr
== MAP_FAILED
) {
63 fprintf(stderr
, "addSection(): Memory allocation failed!\n");
68 Sections
[SectionCount
].Ptr
= Ptr
;
69 Sections
[SectionCount
].Size
= Size
;
70 Sections
[SectionCount
].IsCode
= IsCode
;
75 // Callbacks to create the context for the subsequent functions (not used in
77 void *memCreateContext(void *CtxCtx
) {
78 assert(CtxCtx
== &CtxCtxPlaceholder
&& "Unexpected CtxCtx value");
79 return &CtxPlaceholder
;
82 void memNotifyTerminating(void *CtxCtx
) {
83 assert(CtxCtx
== &CtxCtxPlaceholder
&& "Unexpected CtxCtx value");
86 uint8_t *memAllocate(void *Opaque
, uintptr_t Size
, unsigned Align
, unsigned Id
,
88 printf("Allocated code section \"%s\"\n", Name
);
89 return addSection(Size
, 1);
92 uint8_t *memAllocateData(void *Opaque
, uintptr_t Size
, unsigned Align
,
93 unsigned Id
, const char *Name
, LLVMBool ReadOnly
) {
94 printf("Allocated data section \"%s\"\n", Name
);
95 return addSection(Size
, 0);
98 LLVMBool
memFinalize(void *Opaque
, char **Err
) {
99 printf("Marking code sections as executable ..\n");
100 for (size_t i
= 0; i
< SectionCount
; ++i
) {
101 if (Sections
[i
].IsCode
) {
105 fail
= VirtualProtect(Sections
[i
].Ptr
, Sections
[i
].Size
,
106 PAGE_EXECUTE_READ
, &unused
) == 0;
108 fail
= mprotect(Sections
[i
].Ptr
, Sections
[i
].Size
,
109 PROT_READ
| PROT_EXEC
) == -1;
112 fprintf(stderr
, "Could not mark code section as executable!\n");
120 void memDestroy(void *Opaque
) {
121 assert(Opaque
== &CtxPlaceholder
&& "Unexpected Ctx value");
122 printf("Releasing section memory ..\n");
123 for (size_t i
= 0; i
< SectionCount
; ++i
) {
126 fail
= VirtualFree(Sections
[i
].Ptr
, 0, MEM_RELEASE
) == 0;
128 fail
= munmap(Sections
[i
].Ptr
, Sections
[i
].Size
) == -1;
131 fprintf(stderr
, "Could not release memory for section!");
137 LLVMOrcObjectLayerRef
objectLinkingLayerCreator(void *Opaque
,
138 LLVMOrcExecutionSessionRef ES
,
139 const char *Triple
) {
140 return LLVMOrcCreateRTDyldObjectLinkingLayerWithMCJITMemoryManagerLikeCallbacks(
141 ES
, &CtxCtxPlaceholder
, memCreateContext
, memNotifyTerminating
,
142 memAllocate
, memAllocateData
, memFinalize
, memDestroy
);
145 int handleError(LLVMErrorRef Err
) {
146 char *ErrMsg
= LLVMGetErrorMessage(Err
);
147 fprintf(stderr
, "Error: %s\n", ErrMsg
);
148 LLVMDisposeErrorMessage(ErrMsg
);
152 LLVMOrcThreadSafeModuleRef
createDemoModule(void) {
153 // Create a new ThreadSafeContext and underlying LLVMContext.
154 LLVMOrcThreadSafeContextRef TSCtx
= LLVMOrcCreateNewThreadSafeContext();
156 // Get a reference to the underlying LLVMContext.
157 LLVMContextRef Ctx
= LLVMOrcThreadSafeContextGetContext(TSCtx
);
159 // Create a new LLVM module.
160 LLVMModuleRef M
= LLVMModuleCreateWithNameInContext("demo", Ctx
);
162 // Add a "sum" function":
163 // - Create the function type and function instance.
164 LLVMTypeRef ParamTypes
[] = {LLVMInt32Type(), LLVMInt32Type()};
165 LLVMTypeRef SumFunctionType
=
166 LLVMFunctionType(LLVMInt32Type(), ParamTypes
, 2, 0);
167 LLVMValueRef SumFunction
= LLVMAddFunction(M
, "sum", SumFunctionType
);
169 // - Add a basic block to the function.
170 LLVMBasicBlockRef EntryBB
= LLVMAppendBasicBlock(SumFunction
, "entry");
172 // - Add an IR builder and point it at the end of the basic block.
173 LLVMBuilderRef Builder
= LLVMCreateBuilder();
174 LLVMPositionBuilderAtEnd(Builder
, EntryBB
);
176 // - Get the two function arguments and use them co construct an "add"
178 LLVMValueRef SumArg0
= LLVMGetParam(SumFunction
, 0);
179 LLVMValueRef SumArg1
= LLVMGetParam(SumFunction
, 1);
180 LLVMValueRef Result
= LLVMBuildAdd(Builder
, SumArg0
, SumArg1
, "result");
182 // - Build the return instruction.
183 LLVMBuildRet(Builder
, Result
);
185 // Our demo module is now complete. Wrap it and our ThreadSafeContext in a
187 LLVMOrcThreadSafeModuleRef TSM
= LLVMOrcCreateNewThreadSafeModule(M
, TSCtx
);
189 // Dispose of our local ThreadSafeContext value. The underlying LLVMContext
190 // will be kept alive by our ThreadSafeModule, TSM.
191 LLVMOrcDisposeThreadSafeContext(TSCtx
);
193 // Return the result.
197 int main(int argc
, const char *argv
[]) {
201 // Parse command line arguments and initialize LLVM Core.
202 LLVMParseCommandLineOptions(argc
, argv
, "");
204 // Initialize native target codegen and asm printer.
205 LLVMInitializeNativeTarget();
206 LLVMInitializeNativeAsmPrinter();
208 // Create the JIT instance.
213 LLVMOrcLLJITBuilderRef Builder
= LLVMOrcCreateLLJITBuilder();
214 LLVMOrcLLJITBuilderSetObjectLinkingLayerCreator(
215 Builder
, objectLinkingLayerCreator
, NULL
);
217 if ((Err
= LLVMOrcCreateLLJIT(&J
, Builder
))) {
218 MainResult
= handleError(Err
);
223 // Create our demo module.
224 LLVMOrcThreadSafeModuleRef TSM
= createDemoModule();
226 // Add our demo module to the JIT.
228 LLVMOrcJITDylibRef MainJD
= LLVMOrcLLJITGetMainJITDylib(J
);
230 if ((Err
= LLVMOrcLLJITAddLLVMIRModule(J
, 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
);
239 // Look up the address of our demo entry point.
240 LLVMOrcJITTargetAddress SumAddr
;
243 if ((Err
= LLVMOrcLLJITLookup(J
, &SumAddr
, "sum"))) {
244 MainResult
= handleError(Err
);
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);
254 printf("1 + 2 = %i\n", Result
);
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.
263 if ((Err
= LLVMOrcDisposeLLJIT(J
))) {
264 int NewFailureResult
= handleError(Err
);
266 MainResult
= NewFailureResult
;