You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从LLVM IR的CallInst中获取间接调用的函数名?

如何从LLVM IR的间接CallInst中提取函数名

核心问题说明

间接调用的函数名无法像直接调用那样通过getCalledFunction()直接获取,因为函数指针的目标可能是编译时确定、也可能是运行时动态绑定的,需要分场景处理。


场景1:编译时可确定目标的函数指针(如你的示例)

像你代码里的fun_ptr只被赋值了fun这一个函数,这种情况可以通过回溯数据流追踪指针的赋值来源,找到目标函数:

实现步骤

  1. 从CallInst获取被调用的操作数:CI->getCalledOperand(),这是一个Value*(比如示例中的%3)。
  2. 如果这个操作数是LoadInst(即从指针加载函数地址),进一步获取加载的指针(比如示例中的@fun_ptr全局变量)。
  3. 遍历整个模块,找到所有给该指针赋值的StoreInst,检查被存储的值是否是Function*——如果是,那就是间接调用的目标函数。

修改后的LLVM Pass代码示例

for(Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
{
    for(BasicBlock::iterator BI = BB->begin(), BE = BB->end(); BI != BE; ++BI){
        if (CallInst *CI = dyn_cast<CallInst>(BI)) {
          Function *CF = CI->getCalledFunction();
          if (CF) {
            // 直接调用处理
            std::string fName = CF->getName().str();
            errs() << "Direct call to: " << fName << "\n";
          } else {
            // 间接调用处理
            Value *calledVal = CI->getCalledOperand();
            // 回溯到加载的指针
            if (LoadInst *loadInst = dyn_cast<LoadInst>(calledVal)) {
              Value *ptrOperand = loadInst->getPointerOperand();
              // 处理全局变量类型的函数指针
              if (GlobalVariable *gvPtr = dyn_cast<GlobalVariable>(ptrOperand)) {
                Module &module = *F.getParent();
                // 遍历模块内所有StoreInst,寻找给该全局变量赋值的操作
                for (Function &func : module) {
                  for (BasicBlock &bb : func) {
                    for (Instruction &inst : bb) {
                      if (StoreInst *storeInst = dyn_cast<StoreInst>(&inst)) {
                        if (storeInst->getPointerOperand() == gvPtr) {
                          Value *storedFunc = storeInst->getValueOperand();
                          if (Function *targetFunc = dyn_cast<Function>(storedFunc)) {
                            errs() << "Indirect call to: " << targetFunc->getName() << "\n";
                          }
                        }
                      }
                    }
                  }
                }
              }
              // 可以扩展处理局部变量/参数类型的函数指针,需要更复杂的SSA数据流分析
            }
          }
        }
    }
}

场景2:运行时动态绑定的函数指针

如果函数指针会根据运行时条件被赋值不同函数(比如从用户输入、外部库获取地址),编译阶段无法确定唯一目标,这时有两种方案:

  1. 编译时收集候选函数:使用LLVM的指向分析(如AliasAnalysis框架,或更精确的指针分析算法),找出所有可能被赋值给该指针的函数,作为候选集合。
  2. 离线符号表解析:在LLVM IR阶段记录函数指针的标识符(比如全局变量名@fun_ptr),生成二进制文件后,通过二进制的符号表找到该指针的内存地址,读取其指向的地址值,再映射回符号表中的函数名。这种方式需要结合二进制分析工具(如nm、objdump)或自定义解析逻辑。

局限性说明

  • 上述数据流回溯方法只适用于指针赋值路径简单、目标唯一的场景;如果指针被多次赋值不同函数,需要收集所有可能的目标。
  • 对于局部变量或函数参数传递的函数指针,需要基于LLVM的SSA形式做更深入的数据流分析,追踪每个值的定义链。

内容的提问来源于stack exchange,提问作者Sandesh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 12:01:43