如何在 LLVM C 中使用 LLVMBuildGEP 函数 API
How to use the LLVMBuildGEP function in the LLVM C API
我正在尝试创建一个 LLVM 函数,它从我传递的结构中读取一个字段,我在谷歌上搜索了一些关于 getelementptr 指令的东西,我想这就是我在这里需要的,但它究竟是如何使用的在 C API。
该结构是在 C 中定义的,但我正在尝试通过 LLVM 访问它的字段,因为它们在同一运行时中,我猜它会起作用吗? (如果我错了请纠正我)
这是目前为止的代码。
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <llvm-c/Core.h>
#include <llvm-c/Analysis.h>
#include <llvm-c/ExecutionEngine.h>
typedef struct {
char* name;
int age;
} user;
int main() {
LLVMTypeRef type = LLVMStructCreateNamed(LLVMGetGlobalContext(), "struct.user");
LLVMModuleRef module = LLVMModuleCreateWithName("test");
LLVMBuilderRef builder = LLVMCreateBuilder();
LLVMTypeRef ret = LLVMFunctionType(LLVMPointerType(LLVMInt32Type(), 0),
(LLVMTypeRef[]){ LLVMPointerType(type, 0) }, 1, false);
LLVMValueRef fn = LLVMAddFunction(module, "stuff", ret);
LLVMBasicBlockRef entry = LLVMAppendBasicBlock(fn, "entry");
LLVMPositionBuilderAtEnd(builder, entry);
LLVMValueRef gep = LLVMBuildGEP(builder, LLVMGetParam(fn, 0), (LLVMValueRef[]){ LLVMConstInt(LLVMInt32Type(), 0, false),
LLVMConstInt(LLVMInt32Type(), 1, false) }, 2, "gep");
LLVMBuildRet(builder, gep);
char *error = NULL;
LLVMVerifyModule(module, LLVMAbortProcessAction, &error);
LLVMDisposeMessage(error);
LLVMExecutionEngineRef engine;
error = NULL;
LLVMLinkInMCJIT();
LLVMInitializeNativeTarget();
LLVMInitializeNativeAsmPrinter();
LLVMInitializeNativeAsmParser();
if(LLVMCreateExecutionEngineForModule(&engine, module, &error) != 0) {
fprintf(stderr, "failed to create execution engine\n");
abort();
}
if(error) {
fprintf(stderr, "error: %s\n", error);
LLVMDisposeMessage(error);
exit(EXIT_FAILURE);
}
user m;
m.name = "John";
m.age = 17;
int* (*stuff)(user*) = (int* (*)(user*)) LLVMGetFunctionAddress(engine, "stuff");
printf("%d\n", *stuff(&m));
LLVMDisposeBuilder(builder);
LLVMDisposeExecutionEngine(engine);
return 0;
}
基本上我要构建的函数在 C
中是这样的
int* stuff(user* u) {
return &u->age;
}
所以它因分段错误而崩溃,我已经使用 GDB 对其进行了调试,它似乎发生在我执行 BuildGEP 调用的行中,并出现以下来自 LLVM 共享库的错误
Program received signal SIGSEGV, Segmentation fault.
0xb533baec in llvm::PointerType::get(llvm::Type*, unsigned int) ()
现在我不知道我在做什么。
我需要回答的主要 2 个问题:
你如何使用 C API 中的 LLVMBuildGEP?
我认为这是完全错误的吗?
LLVMStructCreateNamed 创建一个不透明的结构类型(就像 struct user;
在 C 中那样),这意味着 LLVM 不知道里面的元素是什么。您需要使用定义填充该结构,可能使用 LLVMStructSetBody。所以像:
LLVMTypeRef struct_user_members[] = {
LLVMPointerType(LLVMInt8Type(), 0),
LLVMInt32Type()
};
LLVMStructSetBody(type, struct_user_members, 2, false);
在那之后,LLVMBuildGEP 应该能够取消对成员的引用,在我看来你已经做对了。
我正在尝试创建一个 LLVM 函数,它从我传递的结构中读取一个字段,我在谷歌上搜索了一些关于 getelementptr 指令的东西,我想这就是我在这里需要的,但它究竟是如何使用的在 C API。 该结构是在 C 中定义的,但我正在尝试通过 LLVM 访问它的字段,因为它们在同一运行时中,我猜它会起作用吗? (如果我错了请纠正我)
这是目前为止的代码。
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <llvm-c/Core.h>
#include <llvm-c/Analysis.h>
#include <llvm-c/ExecutionEngine.h>
typedef struct {
char* name;
int age;
} user;
int main() {
LLVMTypeRef type = LLVMStructCreateNamed(LLVMGetGlobalContext(), "struct.user");
LLVMModuleRef module = LLVMModuleCreateWithName("test");
LLVMBuilderRef builder = LLVMCreateBuilder();
LLVMTypeRef ret = LLVMFunctionType(LLVMPointerType(LLVMInt32Type(), 0),
(LLVMTypeRef[]){ LLVMPointerType(type, 0) }, 1, false);
LLVMValueRef fn = LLVMAddFunction(module, "stuff", ret);
LLVMBasicBlockRef entry = LLVMAppendBasicBlock(fn, "entry");
LLVMPositionBuilderAtEnd(builder, entry);
LLVMValueRef gep = LLVMBuildGEP(builder, LLVMGetParam(fn, 0), (LLVMValueRef[]){ LLVMConstInt(LLVMInt32Type(), 0, false),
LLVMConstInt(LLVMInt32Type(), 1, false) }, 2, "gep");
LLVMBuildRet(builder, gep);
char *error = NULL;
LLVMVerifyModule(module, LLVMAbortProcessAction, &error);
LLVMDisposeMessage(error);
LLVMExecutionEngineRef engine;
error = NULL;
LLVMLinkInMCJIT();
LLVMInitializeNativeTarget();
LLVMInitializeNativeAsmPrinter();
LLVMInitializeNativeAsmParser();
if(LLVMCreateExecutionEngineForModule(&engine, module, &error) != 0) {
fprintf(stderr, "failed to create execution engine\n");
abort();
}
if(error) {
fprintf(stderr, "error: %s\n", error);
LLVMDisposeMessage(error);
exit(EXIT_FAILURE);
}
user m;
m.name = "John";
m.age = 17;
int* (*stuff)(user*) = (int* (*)(user*)) LLVMGetFunctionAddress(engine, "stuff");
printf("%d\n", *stuff(&m));
LLVMDisposeBuilder(builder);
LLVMDisposeExecutionEngine(engine);
return 0;
}
基本上我要构建的函数在 C
中是这样的int* stuff(user* u) {
return &u->age;
}
所以它因分段错误而崩溃,我已经使用 GDB 对其进行了调试,它似乎发生在我执行 BuildGEP 调用的行中,并出现以下来自 LLVM 共享库的错误
Program received signal SIGSEGV, Segmentation fault.
0xb533baec in llvm::PointerType::get(llvm::Type*, unsigned int) ()
现在我不知道我在做什么。
我需要回答的主要 2 个问题: 你如何使用 C API 中的 LLVMBuildGEP? 我认为这是完全错误的吗?
LLVMStructCreateNamed 创建一个不透明的结构类型(就像 struct user;
在 C 中那样),这意味着 LLVM 不知道里面的元素是什么。您需要使用定义填充该结构,可能使用 LLVMStructSetBody。所以像:
LLVMTypeRef struct_user_members[] = {
LLVMPointerType(LLVMInt8Type(), 0),
LLVMInt32Type()
};
LLVMStructSetBody(type, struct_user_members, 2, false);
在那之后,LLVMBuildGEP 应该能够取消对成员的引用,在我看来你已经做对了。