我刚刚使用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会提供0
或1
,跳转将取决于此。
我无法理解它是如何用于分支的。 有人可以解释这是如何工作的吗?
答案 0 :(得分:11)
当符号发生变化时,JS不跳转,如果符号标志为1,则跳跃。
如果最后一次操作的结果为负,则符号位为on(2的补码中的负数在1中具有最高有效位)。
因此,如果AND运算在两个负整数(-1和-1)之间,则最后一位将为1(符号标志),因此跳转。如果数字为正数,则最后一位为0,则不会进行跳转。
答案 1 :(得分:3)
我不知道你的期望,但是你的程序有未定义的行为,因为a
没有初始化。所以汇编器输出可以是任何东西。
答案 2 :(得分:3)
英特尔手册对此非常有用。这是它为TEST指令记录的内容:
SF是符号标志,是由JS操作码测试的标志。它被设置为这里最重要的eax位,即符号位。因此,当eax包含负数时,将进行跳转。
答案 3 :(得分:2)
如果eax
为负数,则标志将指示在test
指令之后将进行跳转。这会将PC推送到进行打印的.L4
。否则,我们离开。
答案 4 :(得分:2)
test eax, eax
将设置零标志
js指令将基本检查符号标志(a&lt; 0)
答案 5 :(得分:2)
当您指定-O2时,编译器会将您的“int a”放入寄存器以进行速度优化。
由于你从不初始化'int a',程序集不会显示任何写入eax的内容,而是具有最后分配给它的值。
其他答案解释了测试如何作为分支机制。