`printf` 调用发出的 IR 中的段错误

Segfault in emitted IR For `printf` call

我想使用系统 printf 来从我为其编写编译器的编程语言打印单个整数,如 print(3)。我在执行已编译的 IR 时 运行 陷入段错误。

关注,我的代码是

#include "llvm/ADT/APInt.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
#include <vector>

using namespace llvm;

static LLVMContext TheContext;
static IRBuilder<> Builder(TheContext);

int main() {
  static std::unique_ptr<Module> TheModule;
  TheModule = std::make_unique<Module>("inputFile", TheContext);
  std::vector<Type *> Nats(1, Type::getInt32Ty(TheContext));
  FunctionType *PNFT =
      FunctionType::get(Type::getInt32Ty(TheContext), Nats, false);
  Function *PNF = Function::Create(PNFT, Function::ExternalLinkage, "printf",
                                   TheModule.get());
  for (auto &Arg : PNF->args()) {
    Arg.setName("x");
  }
  FunctionType *mainType = FunctionType::get(Builder.getInt32Ty(), false);
  Function *main = Function::Create(mainType, Function::ExternalLinkage, "main",
                                    TheModule.get());
  BasicBlock *entry = BasicBlock::Create(TheContext, "entry", main);
  Builder.SetInsertPoint(entry);

  std::vector<Value *> printArgs;
  printArgs.push_back(ConstantInt::get(TheContext, APInt(32, 20)));
  Builder.CreateCall(TheModule->getFunction("printf"), printArgs);
  Builder.CreateRet(ConstantInt::get(TheContext, APInt(32, 0)));

  TheModule->print(llvm::outs(), nullptr);
}

我用clang++ `llvm-config --cxxflags --ldflags --system-libs --libs all` test.cpp

编译这个

这会输出 LLVM IR

; ModuleID = 'inputFile'
source_filename = "inputFile"

declare i32 @printf(i32)

define i32 @main() {
entry:
  %0 = call i32 @printf(i32 20)
  ret i32 0
}

我将其放入文件 test.ll 并编译为 clang test.ll。我将段错误代码放入 lldb 中,发现 strchr:

中的代码段错误
(lldb) bt
* thread #1, name = 'a.out', stop reason = signal SIGSEGV: invalid address (fault address: 0x14)
  * frame #0: 0x00007ffff7f300fc libc.so.6`__strchrnul_avx2 + 28
    frame #1: 0x00007ffff7e38a53 libc.so.6`__vfprintf_internal + 163
    frame #2: 0x00007ffff7e25a2f libc.so.6`_IO_printf + 175
    frame #3: 0x000055555555514b a.out`main + 11
    frame #4: 0x00007ffff7df5002 libc.so.6`__libc_start_main + 242
    frame #5: 0x000055555555506e a.out`_start + 46

我不认为问题出在编译 IR 上,因为在我的实际代码中(即,不是我在上面显示的 MVE),我直接使用 pass 发出目标代码(如part eight of the kaleidescope tutorial)并且仍然遇到同样的问题。我在这里做错了什么?

谢谢。

感谢@arnt 的评论,我发现 this resource 这导致我将我的程序修改为以下内容:

#include "llvm/ADT/APInt.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
#include <vector>

using namespace llvm;

static LLVMContext TheContext;
static IRBuilder<> Builder(TheContext);

int main() {
  static std::unique_ptr<Module> TheModule;
  TheModule = std::make_unique<Module>("inputFile", TheContext);

  std::vector<llvm::Type *> args;
  args.push_back(llvm::Type::getInt8PtrTy(TheContext));
  llvm::FunctionType *printfType =
      llvm::FunctionType::get(Builder.getInt32Ty(), args, true);
  llvm::Constant *printfFunc = Function::Create(
      printfType, Function::ExternalLinkage, "printf", TheModule.get());

  /*begin codegen for `main`*/
  FunctionType *mainType = FunctionType::get(Builder.getInt32Ty(), false);
  Function *main = Function::Create(mainType, Function::ExternalLinkage, "main",
                                    TheModule.get());
  BasicBlock *entry = BasicBlock::Create(TheContext, "entry", main);
  Builder.SetInsertPoint(entry);

  std::vector<Value *> printArgs;
  llvm::Value *formatStr = Builder.CreateGlobalStringPtr("%d\n");
  printArgs.push_back(formatStr);
  printArgs.push_back(ConstantInt::get(TheContext, APInt(32, 20)));
  Builder.CreateCall(TheModule->getFunction("printf"), printArgs);
  Builder.CreateRet(ConstantInt::get(TheContext, APInt(32, 0)));

  TheModule->print(llvm::outs(), nullptr);
}

这会发出以下 IR:

; ModuleID = 'inputFile'
source_filename = "inputFile"

@0 = private unnamed_addr constant [4 x i8] c"%d[=11=]A[=11=]", align 1

declare i32 @printf(i8*, ...)

define i32 @main() {
entry:
  %0 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @0, i32 0, i32 0), i32 20)
  ret i32 0
}

按预期工作。