红龙书包含,第529页,算法9.1,以及将汇编代码分区为基本块的算法。该算法基本上是:
输入:汇编,作为指令列表。
输出:基本指令块列表
阶段1:标记领导者。 (程序的第一个)是领导者。任何作为分支目标的陈述都是领导者。紧跟在分支之后的任何陈述都是领导者。
阶段2:组装块。要创建基本块,请向块添加一个leader和所有语句,直到遇到另一个leader。这样做直到没有任何陈述。
结束并返回块。
然后,他们使用这种块结构来开发控制流分析。开发的基本结构是控制流程图;它是通过将基本块视为图形中的节点并在块Bi跳转到Bj时从块Bi到Bj创建有向边缘而制作的。
Cooper,Harvey和Waterman(在根据预定代码构建控制流图中)指出,如果跳转到存储器地址或寄存器中保存的位置,则用于创建控制流图的算法是不够的。
这提出了几个问题。何时汇编可以包含分支到内存中的某个位置?什么是预定代码?从x86构建控制流图时,是否还有其他问题需要注意?直接从x86构建控制流图的最着名的算法/实现是什么?
答案 0 :(得分:3)
有几种情况下,对寄存器的内容(或可变内容,就此而言)执行分支
以下是函数指针调用(64位Mac OS)的示例:
C代码
int fptr_call( int (*ptr)(int) ) {
return (*ptr)( 3 );
}
装配
_fptr_call:
0000000100000e70 pushq %rbp
0000000100000e71 movq %rsp, %rbp
0000000100000e74 subq $0x10, %rsp
0000000100000e78 movl $0x3, %eax
0000000100000e7d movq %rdi, 0xfffffffffffffff8(%rbp)
0000000100000e81 movl %eax, %edi
; Call based on %rbp, copied from %rdi which is ptr
0000000100000e83 callq *0xfffffffffffffff8(%rbp)
0000000100000e86 addq $0x10, %rsp
0000000100000e8a popq %rbp
0000000100000e8b ret
0000000100000e8c nopl (%rax)