gpt4 book ai didi

c++ - 当我尝试发出目标代码时,为什么 LLVM 会出现段错误?

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:18:51 26 4
gpt4 key购买 nike

我正在尝试按照有关编译器实现的 LLVM 教程进行操作,但是当我尝试发出目标代码时我的代码出现了段错误。

这是一个尝试编译函数 func 的最小示例。为简单起见,func 是一个什么都不做的函数。

#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 版。

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 时发生段错误。

我尝试使用 GDB 单步执行代码。这是段错误发生时的回溯。

#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 的执行出现问题。

我尝试做的事情在概念上或实现上是否有明显的错误?

最佳答案

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

define void @func() {
entry:
ret void
}

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

此外,llvm::verifyFunction 没有明显地输出错误,因为您没有传递第二个参数,该参数指示 LLVM 应该将错误输出到的流。试试这个而不是输出到 stderr:

llvm::verifyFunction(*func, &llvm::errs())

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

参见:http://llvm.org/docs/doxygen/html/namespacellvm.html#a26389c546573f058ad8ecbdc5c1933cfhttp://llvm.org/docs/doxygen/html/raw__ostream_8h.html

您还应该考虑在生成目标文件之前通过调用 llvm::verifyModule(theModule, theOsStream) 验证整个模块(参见 http://llvm.org/docs/doxygen/html/Verifier_8h.html)。

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

// test.c
void func(void) {}

然后编译查看如下:

clang -S -emit-llvm test.c
cat test.ll

giving :

define dso_local void @_Z4funcv() #0 !dbg !7 {
ret void, !dbg !11
}

attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }

关于c++ - 当我尝试发出目标代码时,为什么 LLVM 会出现段错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42802118/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com