|
板凳

楼主 |
发表于 2009-12-13 12:07:34
|
只看该作者
使用标志位
如果希望程序按照结果正确跳转,那么需要了解标志位的相关状态。
1、使用零标志
如果零标志被置1 (两个操作数相等),JE 和 JZ 指令就跳转到分支。零标志可以由 CMP 指令设置,也可以由计算结果为零的数学指令设置。如:movl $30, %eax
subl $30, %eax
jz overthere SUB 相减结果为 0,JZ 指令被执行。
递减寄存器,当寄存器中的值为 0 时,零标志也会置位:movl $10, %edi
loop1:
< other code instructions >
dec %edi
jz out
jmp loop1
out: 当 EDI 寄存器中的值由 10 减到 1 时,JZ 指令执行,程序退出循环。
2、使用溢出标志
溢出标志专门用在处理带符号数字时。当带符号值对于包含它的数据元素来说太大时,溢出标志被设置为 1 。这经常发生在溢出了保存数据的寄存器长度的数学操作的过程中,如下所示:
.section .text
.global _start
_start:
nop
movl $1, %eax #move 1 to the EAX register
movb $0x7f, %bl #move the signed value 127 to the 8-bit BL register
addb $10, %bl #add 10 to the BL register
jo overthere
int $0x80
overthere:
movl $0, %ebx #move 0 to the EBX register
int $0x80 调试时,在执行 addb $10, %bl 后,查看标志位寄存器可以看到 eflags 0xa92 [ AF SF IF OF ] 可见,发生了溢出。这个程序中,把带符号字节值 127 加上 10,结果应该是 137,这对于字节来说是合法值,但对带符号字节数则是非法的 (带符号字节数只能使用 -127 到 127 的值)。因为这个带符号值非法,所以设置溢出标志为 1,并且执行 JO 指令。
3、使用奇偶校验标志
奇偶校验标志表明数学运算答案中应该为 1 的位的数目。可以使用它作为粗略的错误检查系统,确保数学操作成功执行。
如果结果中被设置为 1 的位的树木是偶数,则设置奇偶校验位 (置1);如果设置为 1 的位的数目是奇数,则不设置奇偶校验位 (置0)。
测试程序(奇偶校验标志位不设置情况):
.section .text
.global _start
_start:
movl $1, %eax
movl $4, %ebx
subl $3, %ebx
jp overthere
int $0x80
overthere:
movl $100, %ebx
int $0x80 运行输出:$ ./paritytest
$ echo $?
1 由此可以看到,程序并没有跳转,这是因为计算结果为 1,以二进制表示是 00000001 。因为 1 的位数是奇数,所以不设置奇偶校验位,JP 指令不会跳转到分支,程序退出。
测试相反情况,改变 SUB 指令这一行,得到的结果为 3,二进制表示为 00000011 。这时因为 1 的位数是偶数,所以设置了奇偶校验位,指令 JP 发生跳转来到 overthere 标签分支,并最后退出时带处的结果代码为 100:$ ./paritytest
$ echo $?
100
4、使用符号标志
符号标志使用在带符号数中,用于表示寄存器中包含的值的符号改变。在带符号数中,最后一位 (最高位)用作符号位。它表明数字表示的是负数(设置为1)还是整数(设置为0).
当在循环内进行计数并且监视零值时,这个标志很有用。
在循环计数中,在寄存器中的值递减为 0 时,零标志位被设立。但是,如果正在处理的是数组,很可能也需要在零值后才停止,而不是在到达零值的位置时停止(因为数组的第一个下标为0)。使用符号标志,可以得到值从 0 到 -1 的变化通知,如下测试程序所示:
.section .text
.global _start
_start:
movl $1, %eax
movl $4, %ebx
subl $3, %ebx
jp overthere
int $0x80
overthere:
movl $100, %ebx
int $0x80 运行与输出:$ ./signtest
The value is: 2
The value is: 10
The value is: 80
The value is: 32
The value is: 50
The value is: 6
The value is: 11
The value is: 34
The value is: 15
The value is: 21 程序反向遍历数据数组,使用 EDI 寄存器作为变址,处理每个数组元素时递减这个寄存器。使用 JNS 指令检查 EDI 寄存器的值什么时候变成负值,如果不是负值,则返回到循环开头。
5、使用进位标志
进位标志用在数学表达式中,表示无符号数何时发生溢出(注意,带符号数使用溢出标志)。当指令导致寄存器超出其数据长度限制时设置进位标志。
和溢出标志不同,DEC 和 INC 指令不影响进位标志。例如,下面代码片段不会设置标志位:movl $0xffffffff, %ebx
inc %ebx
jc overflow 但是,下面的这个代码片段会设置进位标志,并且 JC 指令会跳转到 overflow 的位置:movl $0xffffffff, %ebx
addl $1, %ebx
jc overflow 无符号值小于零时也会设置进位标志,如:movl $2, %eax
subl $4, %eax
jc overflow EAX 寄存器中的结果值是 254,作为带符号数,它代表 -2 ,即正确的答案。这就是说不会设置溢出标志。但是,对于无符号数来说,答案小于零,所以设置进位标志。
和其他标志不同,有可以专门修改进位标志的指令,如下表所示:
指令
| 描述
| CLC
| 清空进位标志(设置它为零)
| CMC
| 对进位标志求反(把它改变为相反的值)
| STC
| 设置进位标志(设置它为1)
| 上面几个指令都直接修改 EFLAGS 寄存器中的进位标志位。 |
|