如何在LLVM IR程序中查找address-taken变量和top-level变量
在LLVM IR中识别top-level变量与address-taken变量
定义回顾
- top-level变量:无法通过指针间接访问的变量,其地址从未通过取址操作暴露,也不是动态内存分配返回的变量。
- address-taken变量:地址已被暴露(如被取址后存储到其他指针、作为函数参数传递),可通过指针间接访问的变量。
示例说明
以下LLVM IR代码中,a是top-level变量,b、c是address-taken变量:
a = alloca i8** b = alloca i8* c = alloca i8 store b a store c b store 0 c
原因:b的地址被存储到a中,c的地址被存储到b中,二者地址均已暴露;而a的地址从未被任何操作暴露,只能直接对其进行加载/存储操作,无法通过其他指针间接访问。
识别方法
1. 手动分析LLVM IR
对于小规模IR代码,可通过逐行检查变量的使用场景判断:
- 遍历所有
alloca指令(栈上变量):- 若变量仅被用于直接加载/存储其值(如
store 0 c中的c是作为存储目标,而非被存储的地址),且从未被取址后存储到其他指针、传递给函数,则为top-level变量。 - 若变量的地址被存储到其他指针(如
store b a中的b)、作为函数参数传递,或被取址后用于其他指针操作,则为address-taken变量。
- 若变量仅被用于直接加载/存储其值(如
- 动态内存分配(如
malloc)返回的指针:这类变量的地址天然是暴露的,属于address-taken变量。 - 全局变量:所有全局变量的地址默认可被访问,均为address-taken变量(除非是
private属性且从未被取址使用,这类情况极少)。
2. 用LLVM Pass自动化分析
对于大规模IR程序,手动分析效率极低,可编写LLVM Pass自动识别:
以下是一个简单的FunctionPass实现,用于分析函数内的栈上变量:
#include "llvm/IR/Function.h" #include "llvm/Pass.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; namespace { struct VarAnalysisPass : public FunctionPass { static char ID; VarAnalysisPass() : FunctionPass(ID) {} bool runOnFunction(Function &F) override { errs() << "Analyzing function: " << F.getName() << "\n"; for (auto &BB : F) { for (auto &I : BB) { if (AllocaInst *AI = dyn_cast<AllocaInst>(&I)) { bool isAddressTaken = false; // 遍历当前alloca的所有使用场景 for (auto &Use : AI->uses()) { User *U = Use.getUser(); // 排除直接加载/存储变量值的情况 if (!isa<LoadInst>(U) && !isa<StoreInst>(U, Use.getOperandNo())) { isAddressTaken = true; break; } // 检查是否存在存储该变量地址的操作 if (StoreInst *SI = dyn_cast<StoreInst>(U)) { if (SI->getValueOperand() == AI) { isAddressTaken = true; break; } } } if (isAddressTaken) { errs() << " Address-taken variable: " << *AI << "\n"; } else { errs() << " Top-level variable: " << *AI << "\n"; } } } } return false; } }; } char VarAnalysisPass::ID = 0; static RegisterPass<VarAnalysisPass> X("var-analysis", "Analyze top-level and address-taken variables");
逻辑说明
该Pass遍历函数内的每个基本块与指令,对每个alloca指令:
- 检查其所有使用场景,若存在存储变量地址、作为非加载/存储类指令的操作数(如传递给函数),则标记为address-taken变量。
- 若仅被用于直接加载或存储其值,则标记为top-level变量。
内容的提问来源于stack exchange,提问作者heturing
相关产品推荐
相关产品推荐

