Мне нужно реализовать библиотеку, которая компилирует код C в байт-код eBPF, используя LLVM/Clang в качестве бэкэнд. Коды будут считаны из памяти, и мне также нужно получить результирующий код сборки в памяти.Создайте сборку из C-кода в памяти с помощью libclang
До сих пор я был в состоянии собрать в LLVM IR, используя следующий код:
#include <string>
#include <vector>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Basic/DiagnosticOptions.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <clang/CodeGen/CodeGenAction.h>
#include <clang/Basic/TargetInfo.h>
#include <llvm/Support/TargetSelect.h>
using namespace std;
using namespace clang;
using namespace llvm;
int main() {
constexpr auto testCodeFileName = "test.cpp";
constexpr auto testCode = "int test() { return 2+2; }";
// Prepare compilation arguments
vector<const char *> args;
args.push_back(testCodeFileName);
// Prepare DiagnosticEngine
DiagnosticOptions DiagOpts;
TextDiagnosticPrinter *textDiagPrinter =
new clang::TextDiagnosticPrinter(errs(),
&DiagOpts);
IntrusiveRefCntPtr<clang::DiagnosticIDs> pDiagIDs;
DiagnosticsEngine *pDiagnosticsEngine =
new DiagnosticsEngine(pDiagIDs,
&DiagOpts,
textDiagPrinter);
// Initialize CompilerInvocation
CompilerInvocation *CI = new CompilerInvocation();
CompilerInvocation::CreateFromArgs(*CI, &args[0], &args[0] + args.size(), *pDiagnosticsEngine);
// Map code filename to a memoryBuffer
StringRef testCodeData(testCode);
unique_ptr<MemoryBuffer> buffer = MemoryBuffer::getMemBufferCopy(testCodeData);
CI->getPreprocessorOpts().addRemappedFile(testCodeFileName, buffer.get());
// Create and initialize CompilerInstance
CompilerInstance Clang;
Clang.setInvocation(CI);
Clang.createDiagnostics();
// Set target (I guess I can initialize only the BPF target, but I don't know how)
InitializeAllTargets();
const std::shared_ptr<clang::TargetOptions> targetOptions = std::make_shared<clang::TargetOptions>();
targetOptions->Triple = string("bpf");
TargetInfo *pTargetInfo = TargetInfo::CreateTargetInfo(*pDiagnosticsEngine,targetOptions);
Clang.setTarget(pTargetInfo);
// Create and execute action
// CodeGenAction *compilerAction = new EmitLLVMOnlyAction();
CodeGenAction *compilerAction = new EmitAssemblyAction();
Clang.ExecuteAction(*compilerAction);
buffer.release();
}
Для компиляции я использую следующий CMakeLists.txt:
cmake_minimum_required(VERSION 3.3.2)
project(clang_backend CXX)
set(CMAKE_CXX_COMPILER "clang++")
execute_process(COMMAND llvm-config --cxxflags OUTPUT_VARIABLE LLVM_CONFIG OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND llvm-config --libs OUTPUT_VARIABLE LLVM_LIBS OUTPUT_STRIP_TRAILING_WHITESPACE)
set(CMAKE_CXX_FLAGS ${LLVM_CONFIG})
set(CLANG_LIBS clang clangFrontend clangDriver clangSerialization clangParse
clangCodeGen clangSema clangAnalysis clangEdit clangAST clangLex
clangBasic)
add_executable(clang_backend main.cpp)
target_link_libraries(clang_backend ${CLANG_LIBS})
target_link_libraries(clang_backend ${LLVM_LIBS})
Если я правильно понял, Я должен иметь возможность генерировать код сборки, если я изменяю действие компилятора на EmitAssemblyAction(), но я, вероятно, не инициализирую что-то, поскольку получаю ошибку сегментации в llvm :: TargetPassConfig :: addPassesToHandleExceptions (this = this @ entry = 0x6d8d30) в /tmp/llvm-3.7.1.src/lib/CodeGen/Pas ses.cpp: 419
код на этой линии:
switch (TM->getMCAsmInfo()->getExceptionHandlingType()) {
Кто-нибудь есть пример или знает, что я не хватает?
Я думаю, вам нужно придумать полный пример, который может быть скомпилирован и протестирован ... –
Компилируемый пример добавлен. –
После исправления опечатки я получаю сообщение об ошибке «Неустранимая ошибка: не удалось переделать файл« test.cpp »в содержимое файла« int test() {return 2 + 2; } '' –