什么构成基本块的开始?

时间:2013-07-16 18:30:11

标签: assembly x86 x86-64

汇编代码中无条件跳转后的指令是否构成新基本块的开始?假设指令不是可执行文件中任何分支的目标。

2 个答案:

答案 0 :(得分:3)

由于计算分支的可能性,并且可能总是或永远不会遵循条件分支,因此不可能完美地确定什么构成基本块。相反,使用两个假设来估计基本块:

  1. 由于其他原因,计算出的分支只会到达基本块的开头,因此不需要知道它们的目标。
  2. 可以遵循条件分支,但不遵循条件分支。
  3. 使用Wikipedia's definition,基本块只能在开头输入并在结尾退出,从开始到结束只有一条路径。因此,任何条件跳转指令必须是基本块的结尾,因为它创建了两个路径。计算分支也是结束,因为它们可以产生许多不同的路径。

    无条件跳转是否是基本块的结束可以使用稍微不同的定义进行争论。如果块中的所有代码必须在内存中是连续的,那么无条件跳转始终是结束,除非它转到它之后的指令。否则,它遵循与非跳转指令相同的规则。

    对于所有其他指令,如果在它之后执行的指令是基本块的开始,那么它必须是一个指令的结束。

    块的最简单的开始是程序的入口点。另外,作为条件跳转的目标的任何指令都是块的开始,因为它可以在跳转指令之后执行或不执行。如果一条指令是无条件跳转的目标,并且基本块必须在内存中是连续的,那么它就是一个块的开始。否则,如果它是两个或多个无条件跳转的目标,或者它是一个目标并且它之前的指令不是无条件跳转,那么它就是一个块的开始,因为它有多条路径。

    如果无条件跳转后的指令不是任何其他跳转的目标,它仍可能被标记为基本块的开头,因为它的存在表明计算的分支可能会以它为目标。

    基本块启动的这些规则基本上简化为“在基本块结束后执行的指令是基本块的开始”。

    一个更简单的方法,有时会产生更小的块,但通常是好的,是任何跳转都是一个块的结束,并且它之后的指令是一个的开始,而任何跳转的目标是一个开始一个块和它之前的指令是一个结束。


    如果有更高级别的代码可用,则可以更准确地确定块边界。例如,编译器生成的计算分支通常具有一组已知的可能目标。请考虑以下C代码:

    int i, j, k;
    switch(i) {
        case 0:
            j++;
            // Flow into the next case
        case 1:
            k++;
    }
    

    以下是使用计算分支的此代码的一些可能的伪装配:

    jump    *(i+jumpTable)
    add     1, j
    add     1, k
    

    跳转表将针对其中一个添加指令,因此它们都是基本块的开头。但是,这不能从组件中确定,因此使用了第一个假设。第一个添加是基本块的开始,因为它是在跳转之后。但是,没有已知的分支针对第二个添加,因此通过此分析不会将其视为基本块的开始。

答案 1 :(得分:2)

跟随无条件跳转并且不是任何分支或跳转的目标的指令是死代码或仅仅是数据。