c++ - Generate assembly from C code in memory using libclang -


i need implement library compiles c code ebpf bytecode using llvm/clang backend. codes read memory , need resultant assembly code in memory too.

until now, have been able compile llvm ir using following code:

#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 memorybuffer     stringref testcodedata(testcode);     unique_ptr<memorybuffer> buffer = memorybuffer::getmembuffercopy(testcodedata);     ci->getpreprocessoropts().addremappedfile(testcodefilename, buffer.get());       // create , initialize compilerinstance     compilerinstance clang;     clang.setinvocation(ci);     clang.creatediagnostics();      // set target (i guess can initialize bpf target, 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 , execute action     // codegenaction *compileraction = new emitllvmonlyaction();     codegenaction *compileraction = new emitassemblyaction();     clang.executeaction(*compileraction);      buffer.release(); } 

to compile use following 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}) 

if understood correctly, should able generate assembly code if change compiler action emitassemblyaction(), i'm not initializing i'm getting segmentation fault in llvm::targetpassconfig::addpassestohandleexceptions (this=this@entry=0x6d8d30) @ /tmp/llvm-3.7.1.src/lib/codegen/passes.cpp:419

the code @ line is:

switch (tm->getmcasminfo()->getexceptionhandlingtype()) { 

does have example or knows i'm missing?

so, if compile llvm asserts on, error clearer, , tell need do:

x: .../src/llvm/lib/codegen/llvmtargetmachine.cpp:63:  void llvm::llvmtargetmachine::initasminfo():  assertion `tmpasminfo && "mcasminfo not initialized. "  "make sure include correct targetselect.h"  "and initializealltargetmcs() being invoked!"' failed. 

(i added line-breaks that, since printed single long line).

after adding required initializealltargetmcs() @ beginning of main, got error. looking @ object file generation of compiler, "guessed" problem initializeall* call. little bit of testing, , turns out need initializeallasmprinters(); - makes sense given want produce assembly code.

i'm not entirely sure how "see" results code, adding 2 beginning of main makes run completion rather assert, exit error or crash - typically step in right direction.

so main looks in "my" code:

int main() {      constexpr auto testcodefilename = "test.cpp";     constexpr auto testcode = "int test() { return 2+2; }";      initializealltargetmcs();     initializeallasmprinters();      // 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 memorybuffer     stringref testcodedata(testcode);     unique_ptr<memorybuffer> buffer = memorybuffer::getmembuffercopy(testcodedata);     ci->getpreprocessoropts().addremappedfile(testcodefilename, buffer.get());       // create , initialize compilerinstance     compilerinstance clang;     clang.setinvocation(ci);     clang.creatediagnostics();      // set target (i guess can initialize bpf target, 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 , execute action     // codegenaction *compileraction = new emitllvmonlyaction();     codegenaction *compileraction = new emitassemblyaction();     clang.executeaction(*compileraction);      buffer.release(); } 

i suggest if want develop clang&llvm, build debug version of clang&llvm - both in tracking down "why" , catch problems , more obvious. use -dcmake_build_type=debug cmake flavour.

my complete script getting llvm & clang build:

export cc=clang export cxx=clang++  cmake -dcmake_build_type=debug -dcmake_install_prefix=/usr/local/llvm-debug -dllvm_tar gets_to_build=x86 ../llvm 

[i using late pre-release of 3.8 test this, doubt it's different 3.7.1 in respect]


Comments

Popular posts from this blog

get url and add instance to a model with prefilled foreign key :django admin -

css - Make div keyboard-scrollable in jQuery Mobile? -

ruby on rails - Seeing duplicate requests handled with Unicorn -