问题
I'm trying to follow along with the LLVM tutorial on compiler implementation, but my code segfaults when I try to emit object code.
Here's a minimal example that attempts to compile a function func
. To keep things simple, func
is a function that does nothing.
#include <iostream>
#include <llvm/ADT/Optional.h>
#include <llvm/IR/BasicBlock.h>
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Type.h>
#include <llvm/IR/Verifier.h>
#include <llvm/Support/CodeGen.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/Host.h>
#include <llvm/Support/TargetRegistry.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/raw_ostream.h>
#include <llvm/Target/TargetMachine.h>
#include <llvm/Target/TargetOptions.h>
#include <stdexcept>
#include <string>
#include <system_error>
#include <vector>
int main() {
llvm::LLVMContext context;
llvm::IRBuilder<> builder(context);
llvm::Module module("module", context);
llvm::Function* const func = llvm::Function::Create(
llvm::FunctionType::get(llvm::Type::getVoidTy(context),
std::vector<llvm::Type*>(), false),
llvm::Function::ExternalLinkage, "func", &module
);
builder.SetInsertPoint(llvm::BasicBlock::Create(context, "entry", func));
llvm::verifyFunction(*func);
func->dump();
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmParsers();
llvm::InitializeAllAsmPrinters();
const std::string triple = llvm::sys::getDefaultTargetTriple();
std::string message;
const llvm::Target* const target = llvm::TargetRegistry::lookupTarget(
triple, message
);
if (!target) throw std::runtime_error("Couldn't find target.");
llvm::TargetMachine* const machine = target->createTargetMachine(
triple, "generic", "", llvm::TargetOptions(),
llvm::Optional<llvm::Reloc::Model>()
);
module.setDataLayout(machine->createDataLayout());
module.setTargetTriple(triple);
std::error_code code;
llvm::raw_fd_ostream obj_file("func.o", code, llvm::sys::fs::F_None);
if (code) throw std::runtime_error("Couldn't open object file.");
llvm::legacy::PassManager manager;
if (
machine->addPassesToEmitFile(manager, obj_file,
llvm::TargetMachine::CGFT_ObjectFile)
) throw std::runtime_error("Adding passes failed.");
std::cout << "Running pass manager." << std::endl;
manager.run(module);
std::cout << "Ran pass manager." << std::endl;
obj_file.flush();
}
Here's the command I'm compiling with. I'm using GCC version 6.3.1 and LLVM version 3.9.1.
g++ src/main.cc -o bin/test -std=c++1z -Wall -Wextra \
-Wno-unused-function -Wno-unused-value -Wno-unused-parameter \
-Werror -ggdb -O0 `llvm-config --system-libs --libs core`
And here's the output.
define void @func() {
entry:
}
Running pass manager.
Segmentation fault (core dumped)
The translation to IR succeeds--at least to me the dump looks correct--but the segfault occurs on calling llvm::legacy::PassManager::run
.
I tried stepping through the code with GDB. Here's the backtrace from the moment of the segfault.
#0 0x00007ffff56ce72f in ?? () from /usr/lib/libLLVM-3.9.so
#1 0x00007ffff56477c2 in llvm::FPPassManager::runOnFunction(llvm::Function&) () from /usr/lib/libLLVM-3.9.so
#2 0x00007ffff5647b4b in llvm::FPPassManager::runOnModule(llvm::Module&) () from /usr/lib/libLLVM-3.9.so
#3 0x00007ffff5647e74 in llvm::legacy::PassManagerImpl::run(llvm::Module&) () from /usr/lib/libLLVM-3.9.so
#4 0x0000000000403ab6 in main () at src/main.cc:76
Unfortunately, my LLVM installation (installed using pacman
on Arch Linux) doesn't seem to have line-number debugging information, so I can't tell exactly where in llvm::FPPassManager::runOnFunction
's execution the problem is occurring.
Is there anything obviously wrong, either in concept or in implementation, with what I'm trying to do?
回答1:
All LLVM basic blocks must be terminated (see e.g. http://llvm.org/docs/doxygen/html/classllvm_1_1BasicBlock.html#details). In your case, the generated IR should look like this:
define void @func() {
entry:
ret void
}
In your C++ code, you need to add builder.CreateRetVoid()
before you call llvm::verifyFunction
.
Also, llvm::verifyFunction
is not visibly outputting an error because you haven't passed the second parameter which indicates the stream to which LLVM should output errors. Try this instead to output to stderr:
llvm::verifyFunction(*func, &llvm::errs())
You also should check the return value of llvm::verifyFunction
. A true
return value indicates an error.
See: http://llvm.org/docs/doxygen/html/namespacellvm.html#a26389c546573f058ad8ecbdc5c1933cf and http://llvm.org/docs/doxygen/html/raw__ostream_8h.html
You should also consider verifying the entire module before generating object files by calling llvm::verifyModule(theModule, theOsStream)
(see http://llvm.org/docs/doxygen/html/Verifier_8h.html).
Finally, I'd recommend inspecting the IR generated by Clang when compiling C code so that you can inspect what correctly generated IR looks like. For example, you can create a simple C file as follows:
// test.c
void func(void) {}
And then compile and view as follows:
clang -S -emit-llvm test.c
cat test.ll
来源:https://stackoverflow.com/questions/42802118/why-is-llvm-segfaulting-when-i-try-to-emit-object-code