理解装配:-O2如果分支

时间:2011-01-11 14:56:38

标签: c assembly disassembly

我刚刚使用if语句尝试了一个简单的C程序并分析了它的程序集。但是,当使用-O2标志进行编译时,它的行为会有很大不同。

相同的C代码是: -

#include<stdio.h>

int main(int argc, char **argv) {
    int a;

    if(a<0) {
        printf("A is less than 0\n");
    }
}

相应的程序集是: -

main:
    push    %ebp
    mov %ebp, %esp
    sub %esp, 8
    and %esp, -16
    sub %esp, 16
    test    %eax, %eax
    js  .L4
    leave
    ret
    .p2align 4,,15
.L4:
    sub %esp, 12
    push    OFFSET FLAT:.LC0
    call    puts
    add %esp, 16
    leave
    ret
    .size   main, .-main
    .section    .note.GNU-stack,"",@progbits
    .ident  "GCC: (GNU) 3.4.6"

我读到test指令基本上只执行两个操作数的逻辑AND。我还读到,当前一条指令中的符号发生变化时,js指令会执行跳转。因此,使用eax test eax会提供01,跳转将取决于此。

我无法理解它是如何用于分支的。 有人可以解释这是如何工作的吗?

6 个答案:

答案 0 :(得分:11)

当符号发生变化时,JS不跳转,如果符号标志为1,则跳跃。

如果最后一次操作的结果为负,则符号位为on(2的补码中的负数在1中具有最高有效位)。

因此,如果AND运算在两个负整数(-1和-1)之间,则最后一位将为1(符号标志),因此跳转。如果数字为正数,则最后一位为0,则不会进行跳转。

答案 1 :(得分:3)

我不知道你的期望,但是你的程序有未定义的行为,因为a没有初始化。所以汇编器输出可以是任何东西。

答案 2 :(得分:3)

英特尔手册对此非常有用。这是它为TEST指令记录的内容:

alt text

SF是符号标志,是由JS操作码测试的标志。它被设置为这里最重要的eax位,即符号位。因此,当eax包含负数时,将进行跳转。

答案 3 :(得分:2)

如果eax为负数,则标志将指示在test指令之后将进行跳转。这会将PC推送到进行打印的.L4。否则,我们离开。

答案 4 :(得分:2)

如果eax = 0

test eax, eax将设置零标志

js指令将基本检查符号标志(a&lt; 0)

答案 5 :(得分:2)

当您指定-O2时,编译器会将您的“int a”放入寄存器以进行速度优化。

由于你从不初始化'int a',程序集不会显示任何写入eax的内容,而是具有最后分配给它的值。

其他答案解释了测试如何作为分支机制。