LLVM一个简单的Pass
1 // Before : 2 // entry 3 // | 4 // ______v______ 5 // | switch | 6 // |_____________| 7 // | 8 // +---------------+ 9 // | _____________ 10 // +------->| case1 |-------+ 11 // | |_____________| | 12 // +------->| case2 |-------+ 13 // | |_____________| | 14 // +------->| case3 |-------+ 15 // | |_____________| | 16 // +------->| case4 |-------+ 17 // | |_____________| | 18 // +------->| case5 |-------+ 19 // | |_____________| | 20 // +------->| default |-------+ 21 // |_____________| | 22 // | 23 // +--------------+ 24 // | 25 // v 26 // return 27 // 28 // After : 29 // entry 30 // | 31 // ______v______ 32 // +-------(true)--| if1 | 33 // | +----(false)--|_____________| 34 // | | _____________ 35 // | | | else | 36 // | | +---------->|_____________|------------------+ 37 // | | | _____________ | 38 // | | +--(false)--| if5 | | 39 // | | +---------->|_____________|--(true)--------+ | 40 // | | | _____________ | | 41 // | | +--(false)--| if4 | | | 42 // | | +---------->|_____________|--(true)------+ | | 43 // | | | _____________ | | | 44 // | | +--(false)--| if3 | | | | 45 // | | +---------->|_____________|--(true)----+ | | | 46 // | | | _____________ | | | | 47 // | | +--(false)--| if2 | | | | | 48 // | +------------>|_____________|--(true)--+ | | | | 49 // | _____________ | | | | | 50 // +-------------->| run1 | | | | | | 51 // +---------------|_____________| | | | | | 52 // | _____________ | | | | | 53 // +---------------| run2 |<---------+ | | | | 54 // | |_____________| | | | | 55 // | _____________ | | | | 56 // +---------------| run3 |<-----------+ | | | 57 // | |_____________| | | | 58 // | _____________ | | | 59 // +---------------| run4 |<-------------+ | | 60 // | |_____________| | | 61 // | _____________ | | 62 // +---------------| run5 |<---------------+ | 63 // | |_____________| | 64 // | _____________ | 65 // +---------------| run6 |<-----------------+ 66 // | |_____________| 67 // | 68 // +----------------------+ 69 // | 70 // v 71 // return 72 // 73 // 当前模块执行后的整体流程图如上 74 // 当前模块仅支持将LLVM识别的switch 语句修改成 if else 格式, 75 // 但是这种改动对IDA 没有太大影响 76 77 #include "stdafx.h" 78 79 #include "LowerSwitchInst.h" 80 81 82 static llvm::zoo::cl::opt_bool _lsi("LowerSwitchInst", "lsi", false, "改变Switch 语句成if else 格式"); 83 84 static llvm::zoo::cl::opt_str _lsi_name("LowerSwitchInst", "lsi_name", "", "要替换的函数名字"); 85 86 87 namespace zoollvm 88 { 89 LowerSwitchInst::LowerSwitchInst() 90 { 91 _bWorked = false; 92 } 93 94 void LowerSwitchInst::ClearWork() 95 { 96 _bWorked = false; 97 } 98 99 bool LowerSwitchInst::IsWorked() 100 { 101 return _bWorked; 102 } 103 104 bool LowerSwitchInst::Run(llvm::Module &M, llvm::Function &F) 105 { 106 std::vector<llvm::BasicBlock*> _vecDelete; 107 std::vector<llvm::SwitchInst*> _vecDeleteInst; 108 // 删除列表 109 110 ZooPrint("Function Name = [%s] \n", zoollvm::module::function::GetFunctionName(F).c_str()); 111 for (llvm::Function::iterator I = F.begin(), E = F.end(); I != E; I++) 112 { 113 llvm::BasicBlock &Cur = *I; 114 auto i = Cur.getTerminator(); 115 if (i == NULL) 116 { 117 continue; 118 } 119 if (llvm::SwitchInst *SI = llvm::dyn_cast<llvm::SwitchInst>(i)) 120 { 121 _bWorked = true; 122 _vecDelete.push_back(&*I); 123 _vecDeleteInst.push_back(SI); 124 125 ZooPrint("SI = %p \n", SI); 126 ZooPrint(" getOpcodeName : [%s] \n", SI->getOpcodeName()); 127 128 Lower(M, F, Cur, *SI); 129 ZooPrint("\n"); 130 } 131 } 132 ZooPrint("Write Pass Success \n"); 133 for (auto it : _vecDeleteInst) 134 { 135 zoollvm::module::function::block::RemoveBlockSelf(it); 136 } 137 ZooPrint("Delete Inst Success \n"); 138 return true; 139 } 140 141 bool LowerSwitchInst::Lower(llvm::Module &M, llvm::Function &F, llvm::BasicBlock &B, llvm::SwitchInst &S) 142 { 143 llvm::Value *Val = S.getCondition(); 144 struct CaseRange 145 { 146 llvm::ConstantInt* cValue; // 147 llvm::BasicBlock* BB; // 处理块 148 CaseRange(llvm::ConstantInt *low, llvm::BasicBlock *bb) : cValue(low), BB(bb) {} 149 }; 150 std::vector<CaseRange> Cases; 151 ZooPrint(" Value = [%s] \n", Val->getName().str().c_str()); 152 ULONG NumSimpleCases = 0; 153 // 找到所有case 块 154 for (auto Case : S.cases()) 155 { 156 if (Case.getCaseSuccessor() == S.getDefaultDest()) 157 { 158 continue; 159 } 160 Cases.push_back(CaseRange(Case.getCaseValue(), Case.getCaseSuccessor())); 161 ++NumSimpleCases; 162 } 163 ZooPrint(" NumSimpleCases = [%d] \n", NumSimpleCases); 164 165 // 修改所有case 块 166 llvm::BasicBlock *bb = &B; 167 for (auto it : Cases) 168 { 169 int64_t nextValue = it.cValue->getSExtValue(); 170 171 // 创建一个基本块,目前这个基本块位置未知,只是先要有,用它占位 172 auto ba = zoollvm::module::function::block::Create(B.getContext()); 173 174 // 创建一个逻辑指令 175 // v = (Val == nextValue ) 176 // 这个逻辑指令的位置,放在当前块的最后一条指令的位置,即 (llvm::BinaryOperator *)&*(bb->end() --) 177 auto v = zoollvm::op_code::compare::CreateICmpEQ(Val, zoollvm::value::const_value::CreateInt64(M, nextValue), (llvm::BinaryOperator *)&*(bb->end() --)); 178 179 // if v then exec else 空block end 180 // 这个比较指令的位置,放在当前块的最后一条指令,结合上下文,就是放到上面的逻辑指令的下一条处,就是 bb 的 end 处 181 zoollvm::op_code::branch::CreateCondBr(v, it.BB, ba, bb); 182 183 // 插入刚才创建的基本块,位置是当前基本块的下一个位置,即顺序向下执行的话,就是当前新的基本块跟在上面的比较指令后面 184 ba->insertInto(&F, B.getNextNode()); 185 186 // 修改要操作的基本块,下一个循环,下一条指令,都从这个新的基本块里面添加 187 bb = ba; 188 189 ZooPrint(" nextValue = [%I64d] \n", nextValue); 190 } 191 // 最后补一个跳到default 的指令,位置是在最初第一个基本块后面的第一个基本块中 192 // 上面由于添加指令是从上往下加,而添加基本块是从下往上加,所以最后一个新的基本块在第一条指令的下面,这也是最后一个跳转的块 193 zoollvm::op_code::branch::CreateBr(S.getDefaultDest(), B.getNextNode()); 194 195 196 return true; 197 } 198 199 200 class LowerSwitchInstPass : public llvm::ModulePass, public zoollvm::frame::Base 201 { 202 public: 203 static char ID; // pass identification 204 LowerSwitchInstPass() : ModulePass(ID), zoollvm::frame::Base("LowerSwitchInstPass") 205 { 206 zoollvm::opt::GetFunctionNameList(_lsi_name, _vec); 207 } 208 209 210 // 启动当前Pass 211 virtual bool runOnModule(llvm::Module &M) 212 { 213 if (_lsi == false) 214 { 215 return true; 216 } 217 218 LowerSwitchInst lsi; 219 220 for (auto it = M.begin(); it != M.end(); it++) 221 { 222 if (zoollvm::opt::IsFunctionInList(_vec, *it)) 223 { 224 lsi.Run(M, *it); 225 } 226 } 227 228 return true; 229 } 230 231 private: 232 std::vector<std::string> _vec; 233 }; 234 } 235 236 char zoollvm::LowerSwitchInstPass::ID = 0; 237 llvm::Pass * createLowerSwitchInst() 238 { 239 return new zoollvm::LowerSwitchInstPass(); 240 }
由于新版LLVM(9.0.0),无法直接调用Util 自带的 LowerSwitch 了,所以这里,我自己弄了一个,
主要功能是展开Switch,把它变成if else,理论上其实没啥区别,但是实际上在LLVM的角度上看,区别很大,
switch 实际上是一条 instruction ,后面的 case 是和switch 在一起的一条 instruction,
这就导致,如果不对它做处理,那么这个 instruction 是非常大的,由于这一条指令是在一个 block 里面的,所以结构也清晰,
if else 则不同,一片 if else 实际上是一片 block ,不管做什么操作也稍微更容易一些
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」