LLVM 13/14中如何检测全局变量是否为字符串?
LLVM/Clang 13-14中检测全局字符串变量的替代方案
早期LLVM/Clang版本里,我靠GlobalVar->getName()判断全局变量名是否以.str结尾来识别字符串变量,但在13、14版本里,全局变量名变成了类似??_C@_0M@LACCCNMM@hello?5world?$AA@的特殊命名,原方法失效。尝试解析这类名称后还是没法判断,想知道有没有合适的LLVM函数能实现这个检测,或者我的操作哪里有问题?
附示例C代码及编译命令:
// compiled with: clang.exe -std=c99 helloCC.c -o helloCC.exe -mllvm -my_get_strings=1 -flegacy-pass-manager #include <stdio.h> char *xmy1 = "hello world"; int main(int argc, char *argv[]) { printf("%s", xmy1); return 0; }
注:已手动修改LLVM/Clang代码,将自定义Pass添加至PassManagerBuilder.cpp的populateModulePassManager函数中,通过-flegacy-pass-manager参数触发执行。
解决方案
1. 放弃依赖变量名,直接从IR结构判断
LLVM IR中,字符串常量全局变量有明确的类型和初始化特征,不需要靠名称识别:
- 全局变量的类型是
PointerType,指向的是ArrayType,且数组元素为i8(对应C语言的char) - 变量的初始化器(Initializer)是
ConstantDataArray类型,这类对象专门存储字符串或字节常量
示例代码片段:
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(&I)) { // 检查是否为指向i8数组的指针 if (PointerType *PT = dyn_cast<PointerType>(GV->getType())) { if (ArrayType *AT = dyn_cast<ArrayType>(PT->getElementType())) { if (AT->getElementType()->isIntegerTy(8)) { // 检查是否存在常量初始化器 if (Constant *Init = GV->getInitializer()) { if (ConstantDataArray *CDA = dyn_cast<ConstantDataArray>(Init)) { // 确认是字符串常量全局变量 StringRef rawStr = CDA->getAsString(); // 可直接获取字符串内容做后续处理 } } } } } }
2. 关于特殊命名的原因
你看到的??_C@_...不是LLVM层面的混淆,是Windows平台下Clang兼容MSVC的字符串池命名规则生成的名称,这类名称是编译器自动生成的,没有通用的解析规则,所以解混淆的思路不可行。
3. Pass执行阶段的注意事项
确保你的自定义Pass在优化Pass之前运行:LLVM的优化阶段可能会对全局变量做合并、重命名或删除操作,晚于优化阶段执行会导致检测结果不准确。你通过-flegacy-pass-manager使用旧版Pass管理器,只要Pass添加到populateModulePassManager的顺序在优化Pass之前,就不会有问题。
内容的提问来源于stack exchange,提问作者m00nic
相关产品推荐
相关产品推荐

