`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
}
按预期工作。
我想使用系统 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
}
按预期工作。