LLVM IR概述
- 优化是对LLVM IR进行操作:
什么是LLVM IR
- LLVM IR 是一门低级语言,语法类似于汇编
- 任何高级编程语言(如C++)都可以用LLVM IR表示
- 基于LLVM IR可以很方便地进行代码优化
LLVM IR的两种表示方法
- 第一种是人类可以阅读的文本形式,文件后缀为.ll
- 第二种是易于机器处理的二进制格式,文件后缀为.bc
LLVM IR结构
- 源代码被编译为LLVM IR后,具有以下结构:
LLVM IR结构:模块 Module
- 一个源代码对应LLVM IR中的一个模块。
- 头部信息包含程序的目标平台,如X86、ARM等,和一些其他信息。
- 全局符号包含全局变量、函数的定义与声明。
LLVM IR结构:函数 Function
- LLVM IR中的函数表示源代码中的某个函数。
- 参数,顾名思义为函数的参数。
- 一个函数由若干基本块组成,其中函数最先执行的基本块为入口块。
LLVM IR结构:基本块 BasicBlock
- 一个基本块由若干个指令和标签组成。
- 正常情况下,基本块的最后一条指令为跳转指令(br或者switch),或返回指令(retn),也叫作终结指令(Terminator Instruction)。
- PHI指令是一种特殊的指令。
LLVM IR结构
- 了解LLVM IR的结构是我们学习代码混淆的基础,举个例子
- 以函数为基本单位的混淆:控制流平坦化
- 以基本块为基本单位的混淆:虚假控制流
- 以指令为基本单位的混淆:指令替代
LLVM IR常用指令讲解
终结指令 Terminator Instructions
- ret指令
- 函数返回指令,对应C/C++中的return。
- br指令
- br是“分支”的英文branch的缩写,分为非条件分支和条件分支,对应C/C++的if语句
- 无条件分支类似有x86汇编中的jmp指令,条件分支类似于x86汇编中的jnz,je等条件跳转指令。
- ret指令
比较指令
- icmp指令
- 整数或指针的比较指令
- 条件cond可以是eq(相等),ne(不相等),ugt(无符号相等)
- fcmp指令
- 浮点数的比较指令
- 条件cond可以是oeq(ordered and equal),ueq(unordered or equal)
- switch指令
- 分支指令,可看做是br指令的升级版,支持的分支更多,但使用也更复杂,对应C/C++中的switch。
- icmp指令
二元运算 Binary Operations
- add指令
- sub指令
- mul指令
- udiv指令
- 无符号整数除法指令
- sdiv指令
- 有符号整数除法指令
- urem指令
- 无符号整数取余指令
- srem指令
- 有符号整数取余指令
按位二元运算 Bitwise Binary Operations
- shl指令
- 整数左移操作指令
- lshr指令
- 整数右移指令
- ashr指令
- 整数算数右移指令
- and指令
- 整数按位与运算指令
- or指令
- 整数按位或运算指令
- xor指令
- 整数按位异或运算指令
- shl指令
内存访问和寻址操作 Memory Access and Addressing Operations
- alloca指令
- 内存分配指令,在栈中分配一块空间并获得指向该空间的指针,类似与C/C++中的malloc函数
- store指令
- 内存存储指令,向指针指向的内存中存储数据,类似与C/C++中的指针引用后的赋值操作
- alloca指令
类型转换操作 Conversion Operations
- trunc..to指令
- 截断指令,将一种类型的变量截断为另一种类型的变量。
- zext..to指令
- 零扩展指令,将一种类型的变量拓展为另一种类型的变量,高位补0。
- sext..to指令
- 符号位拓展指令,通过复制符号位(最高位)将一种类型的变量拓展为另一种类型的变量。
- trunc..to指令
其他操作 Other Operations
phi指令:由静态单赋值引起的问题
select指令
- ? : 三元运算符
call指令
- call指令用来调用某个函数,对应C/C++中的函数调用,与x86汇编中的call指令类似。