x86中的基本块和控制流程

时间:2014-02-22 21:18:48

标签: compilation x86 code-analysis

红龙书包含,第529页,算法9.1,以及将汇编代码分区为基本块的算法。该算法基本上是:

输入:汇编,作为指令列表。
输出:基本指令块列表

阶段1:标记领导者。 (程序的第一个)是领导者。任何作为分支目标的陈述都是领导者。紧跟在分支之后的任何陈述都是领导者。

阶段2:组装块。要创建基本块,请向块添加一个leader和所有语句,直到遇到另一个leader。这样做直到没有任何陈述。

结束并返回块。

然后,他们使用这种块结构来开发控制流分析。开发的基本结构是控制流程图;它是通过将基本块视为图形中的节点并在块Bi跳转到Bj时从块Bi到Bj创建有向边缘而制作的。

Cooper,Harvey和Waterman(在根据预定代码构建控制流图中)指出,如果跳转到存储器地址或寄存器中保存的位置,则用于创建控制流图的算法是不够的。

这提出了几个问题。何时汇编可以包含分支到内存中的某个位置?什么是预定代码?从x86构建控制流图时,是否还有其他问题需要注意?直接从x86构建控制流图的最着名的算法/实现是什么?

1 个答案:

答案 0 :(得分:3)

有几种情况下,对寄存器的内容(或可变内容,就此而言)执行分支

  1. 跳转表,其中跳转到的地址是使用一些地址/偏移表和寄存器值计算的。
  2. 一个函数指针,例如回调函数,其中要调用的函数作为参数提供给调用者,或存储在某个变量中。
  3. C ++中的虚函数表,其中要调用的函数在编译时是未知的,并且可能在运行时更改。
  4. 以下是函数指针调用(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)