c++ - Why is my LLVM JIT implementation segfaulting? -
i'm trying implement simple jit compiler using llvm, following along tutorial (http://releases.llvm.org/4.0.1/docs/tutorial/buildingajit1.html), , i'm running segfault. i've rewritten code in form minimal (albeit still kinda long) example. example loops through integers 0 through 9 , each 1 attempts compile function prints integer, add module, execute function, , remove module jit. simulate interactive session in user inputs commands such print 0
, print 1
, etc.
#include <array> #include <cstdint> #include <iostream> #include <llvm/executionengine/executionengine.h> #include <llvm/executionengine/jitsymbol.h> #include <llvm/executionengine/orc/compileutils.h> #include <llvm/executionengine/orc/ircompilelayer.h> #include <llvm/executionengine/orc/lambdaresolver.h> #include <llvm/executionengine/orc/objectlinkinglayer.h> #include <llvm/executionengine/sectionmemorymanager.h> #include <llvm/executionengine/runtimedyld.h> #include <llvm/ir/basicblock.h> #include <llvm/ir/constants.h> #include <llvm/ir/derivedtypes.h> #include <llvm/ir/function.h> #include <llvm/ir/globalvalue.h> #include <llvm/ir/globalvariable.h> #include <llvm/ir/irbuilder.h> #include <llvm/ir/llvmcontext.h> #include <llvm/ir/legacypassmanager.h> #include <llvm/ir/mangler.h> #include <llvm/ir/module.h> #include <llvm/ir/type.h> #include <llvm/ir/value.h> #include <llvm/ir/verifier.h> #include <llvm/support/dynamiclibrary.h> #include <llvm/support/targetselect.h> #include <llvm/support/raw_ostream.h> #include <llvm/target/targetmachine.h> #include <llvm/transforms/scalar.h> #include <llvm/transforms/scalar/gvn.h> #include <memory> #include <stdexcept> #include <string> #include <utility> #include <vector> int main() { llvm::initializenativetarget(); llvm::initializenativetargetasmprinter(); llvm::initializenativetargetasmparser(); auto machine = llvm::enginebuilder().selecttarget(); llvm::orc::objectlinkinglayer<> linking_layer; llvm::orc::ircompilelayer<llvm::orc::objectlinkinglayer<>> compile_layer( linking_layer, llvm::orc::simplecompiler(*machine) ); llvm::llvmcontext context; llvm::irbuilder<> builder(context); auto layout = machine->createdatalayout(); auto module = std::make_unique<llvm::module>("module", context); auto manager = std::make_unique<llvm::legacy::functionpassmanager>( module.get() ); ( auto p : { llvm::createinstructioncombiningpass(), llvm::createreassociatepass(), llvm::creategvnpass(), llvm::createcfgsimplificationpass() } ) manager->add(p); module->setdatalayout(layout); llvm::sys::dynamiclibrary::loadlibrarypermanently(nullptr); auto index = llvm::constantint::get(context, llvm::apint(8, 0)); std::vector<llvm::constant*> indices = {index, index}; std::string func_name = "func"; (auto = 0; < 10; ++i) { auto format_str = new llvm::globalvariable( *module, llvm::arraytype::get(llvm::type::getint8ty(context), 4), true, llvm::globalvalue::privatelinkage, llvm::constantdataarray::getstring(context, "%i\n"), "format_str" ); format_str->setalignment(1); auto function = llvm::function::create( llvm::functiontype::get( llvm::type::getvoidty(context), std::vector<llvm::type*>{}, false ), llvm::function::externallinkage, func_name, module.get() ); builder.setinsertpoint( llvm::basicblock::create(context, "entry", function) ); builder.createcall( module->getorinsertfunction( "printf", llvm::functiontype::get( llvm::integertype::getint32ty(context), llvm::pointertype::get(llvm::type::getint8ty(context), 0), true ) ), std::vector<llvm::value*>{ llvm::constantexpr::getgetelementptr( nullptr, format_str, indices ), llvm::constantint::get(context, llvm::apint(32, i)) }, "call" ); builder.createretvoid(); std::string message; llvm::raw_string_ostream message_stream(message); if (llvm::verifyfunction(*function, &message_stream)) throw std::runtime_error(message_stream.str()); auto handle = compile_layer.addmoduleset( std::array<std::unique_ptr<llvm::module>, 1>{std::move(module)}, std::make_unique<llvm::sectionmemorymanager>(), llvm::orc::createlambdaresolver( [&](const std::string& name) { auto symbol = compile_layer.findsymbol(name, false); return symbol ? symbol : llvm::jitsymbol(nullptr); }, [](const std::string& name) { auto address = llvm::rtdyldmemorymanager:: getsymboladdressinprocess(name); return address ? llvm::jitsymbol( address, llvm::jitsymbolflags::exported ) : llvm::jitsymbol(nullptr); } ) ); std::string mangled_name; llvm::raw_string_ostream mangled_name_stream(mangled_name); llvm::mangler::getnamewithprefix( mangled_name_stream, func_name, layout ); ( reinterpret_cast <void(*)()> ( static_cast <intptr_t> ( compile_layer.findsymbol( mangled_name_stream.str(), true ).getaddress() ) ) )(); compile_layer.removemoduleset(handle); } }
the expected output follows.
0 1 2 3 4 5 6 7 8 9
instead this.
0 segmentation fault (core dumped)
according gdb, segfault occuring during call llvm::globalvariable::globalvariable
. here's backtrace.
#0 0x00007ffcdb8b6541 in llvm::globalvariable::globalvariable(llvm::module&, llvm::type*, bool, llvm::globalvalue::linkagetypes, llvm::constant*, llvm::twine const&, llvm::globalvariable*, llvm::globalvalue::threadlocalmode, unsigned int, bool) () /usr/lib/libllvm-4.0.so #1 0x000000010000698a in main () @ main.cc:83
i'm using llvm version 4.0.1 , gcc version 7.1.1 , compiling following command.
g++ -std=c++17 main.cc -o main -o0 -wall -wextra -wno-unused-function \ -wno-unused-value -wno-unused-parameter -werror -ggdb \ `llvm-config --system-libs --libs core`
i'm hoping llvm veteran can find mistake. thanks, guys!
module
initialized before for
loop:
auto module = std::make_unique<llvm::module>("module", context);
then in for
loop:
for(...) { auto format_str = new llvm::globalvariable(*module, ...); ^~~~~~~ ... std::array<std::unique_ptr<llvm::module>, 1>{std::move(module)}, ^~~~~~~~~~~~~~~~~ }
at first iteration access object owned module
(ok) , move it. transfer ownership of managed object away module
.
at second iteration access object managed module
-> crash (because doesn't have managed object anymore)
Comments
Post a Comment