为什么在尝试发出目标代码时LLVM出现段错误? [英] Why is LLVM segfaulting when I try to emit object code?

查看:264
本文介绍了为什么在尝试发出目标代码时LLVM出现段错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试遵循有关编译器实现的LLVM教程,但是当我尝试发出目标代码时,我的代码出现段错误.

I'm trying to follow along with the LLVM tutorial on compiler implementation, but my code segfaults when I try to emit object code.

这是一个尝试编译函数func的最小示例.为简单起见,func是不执行任何操作的函数.

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();

}

这是我正在使用的命令.我正在使用GCC 6.3.1版和LLVM 3.9.1版.

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`

这是输出.

define void @func() {
entry:
}

Running pass manager.
Segmentation fault (core dumped)

到IR的转换成功-至少对我来说转储看起来是正确的-但段错误发生在调用llvm::legacy::PassManager::run时.

The translation to IR succeeds--at least to me the dump looks correct--but the segfault occurs on calling llvm::legacy::PassManager::run.

我尝试逐步使用GDB遍历代码.这是段错误发生时的回溯.

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

不幸的是,我的LLVM安装(在Arch Linux上使用pacman安装)似乎没有行号调试信息,因此我无法确切知道问题在llvm::FPPassManager::runOnFunction的执行位置.

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?

推荐答案

所有LLVM基本块都必须终止(请参见例如 http://llvm.org/docs/doxygen/html/classllvm_1_1BasicBlock.html#details ).在您的情况下,生成的IR应该如下所示:

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
}

在C ++代码中,您需要在调用llvm::verifyFunction之前添加builder.CreateRetVoid().

In your C++ code, you need to add builder.CreateRetVoid() before you call llvm::verifyFunction.

此外,llvm::verifyFunction显然没有输出错误,因为您没有传递第二个参数,该参数指示LLVM应该向其输出错误的流.尝试使用此命令输出到stderr:

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())

您还应该检查llvm::verifyFunction的返回值.返回值true表示错误.

You also should check the return value of llvm::verifyFunction. A true return value indicates an error.

请参阅: http://llvm.org/docs/doxygen/html/namespacellvm.html#a26389c546573f058ad8ecbdc5c1933cf http://llvm.org/docs/doxygen /html/raw__ostream_8h.html

您还应该考虑通过调用llvm::verifyModule(theModule, theOsStream)在生成目标文件之前验证整个模块(请参见 http://llvm.org/docs/doxygen/html/Verifier_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).

最后,我建议在编译C代码时检查Clang生成的IR,以便您可以检查正确生成的IR的外观.例如,您可以创建一个简单的C文件,如下所示:

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

这篇关于为什么在尝试发出目标代码时LLVM出现段错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆