源代码的结构在编译器中往往会在某个环节被转换成CFG,不同的控制语句会生成形形色色的控制流结构,而在后端转换的过程中又会生成许多前端语法无法描述的结构出来,在控制流分析的过程中需要去识别这些结构。这篇文章简单的介绍一些基本结构。
1,基本块(basic block)。基本块是一个执行时连续的语句序列,往往最后会跟一个终结语句,比如跳转,条件跳转或者返回,除了最后一个语句外没有任何的分支或跳转命令。
基本块
2,分支结构(branch)。分支结构由一个条件基本块和两个分支基本块组成,一般语言中的if\while\for都会产生这种结构。
分支结构
根据分支结构的上下文,又可以区分为if-then结构,if-else结构和if-then-else结构。
if-else结构
if-then结构
if-than-else结构
分支结构除了常见的二路分支外,还有n路分支(n>=3),由switch的语义产生,不过很少见到硬件指令集中支持它,往往都是IR指令集中支持。
3,循环结构(loop)。循环结构是一个非常重要的结构。如果在CFG的深度优先生成树(DFST)中有一条指向其祖先的边m->n,则m和n之间的子图构成了一个循环,n被称为循环头部。
循环结构
其中B2被称作循环头,而E1则是DFST中的反向边。
根据循环出口的所在,还可以进一步区分为while循环和do-while循环:
do-while结构
while结构
一般情况下,循环结构只会有一个入口,程序中所有的其他结构想要进入这个循环只能通过这个入口进入,但极少的情况下也会有多个入口:
不可规约循环
上图中,B3和B4都是循环的入口。
如果流图中的所有循环都只有一个入口,则称为可规约流图(reducible),否则就称为不可规约流图(inreducible)。不可规约流图在常规程序中很难见到,但在优化后的程序中可能会频繁出现。
往往不可规约流图中都会有这样一个基本子结构:
不可规约子结构
参考资料:
1,《高级编译器设计与实现》
2,反编译技术与软件逆向分析。