Why is LLVM segfaulting when I try to emit object code?

故事扮演 提交于 2019-12-05 00:59:21

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!