使用LLVM编写整数/字符串输入

4

我试图从AST生成llvm-ir。

为了显示整数输出,我添加了以下内容:

Constant *CalleeF = TheModule->getOrInsertFunction("printf",FunctionType::get(IntegerType::getInt32Ty(Context), PointerType::get(Type::getInt8Ty(Context), 0), true);`

而在调用打印函数时,我写了以下内容,
Value* PrintStmt::codegen(){
  Value* V,*val,*to_print;
  vector<Value *> ArgsV;
  for (unsigned int i = 0, e = outs.size(); i != e; ++i){
     to_print = outs[i]->codegen();
     if(outs[i]->type=="int"){
         val=Builder.CreateGlobalStringPtr("%d");
     }
  ArgsV.push_back(val);
  ArgsV.push_back(to_print);
  V =  Builder.CreateCall(CalleeF, ArgsV, "printfCall");
 }
 return V;
}

我应该写什么类似的代码来获取用户输入,即scanf调用的代码?


我通常使用clang转换基本的c->llvm ir,使用标志"clang -emit-llvm test.c"。它将scanf C转换为llvm ir "declare i32 @__isoc99_scanf(i8*, ...)"。 - Chirag Patel
@lazyCoder 谢谢,但我的目标是为 scanf 调用编写代码生成器。在了解了 LLVM-IR 之后,我该如何做呢? - Harshit Mahajan
1个回答

0

如果要使用scanf函数,你需要先声明它的原型。

llvm::FunctionType *readFnType = llvm::FunctionType::get(builder.getInt32Ty(), true); 
llvm::Function* readfn = llvm::Function::Create(readFnType, llvm::GlobalValue::ExternalLinkage, "scanf", TheModule));

并这样调用它

std::vector<Value*> ArgsV; // holds codegen IR for each argument
std::string StringFormat; // holds string formatting for all arguments
for(auto& arg : Args){
        if(auto v = arg->codegen()){ 
            if(v->getType()->isDoubleTy())
                StringFormat += "%lf "; // 
            else if(v->getType()->isIntegerTy())
                StringFormat += "%d ";
            ArgsV.push_back(symbolTable[arg.name]);
        }else return nullptr;
    }
ArgsV.insert(ArgsV.begin(), builder.CreateGlobalStringPtr(StringFormat));
return builder.CreateCall(TheModule->getFunction("scanf"), ArgsV, "scanfCall");

其中symbolTable是一个变量/参数名称到持有变量堆栈分配地址的Value*的映射。请记住,scanf需要写入的变量的地址,这解释了符号表查找。

值得一提的是,这使得scanf本质上是不安全的。您应该考虑使用fgetsgets函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接