Fork me on GitHub

CSAPP-7

控制

条件码寄存器

条件码寄存器 描述
CF 进位标志寄存器。最近的操作使最高位产生了进位,无符号操作溢出时为1
ZF 零标志寄存器。最近的操作得出的结果是0时为1
SF 符号标志寄存器。最近的操作得到的结果为负数时为1
OF 溢出标志寄存器。最近的操作导致一个补码溢出时为1
  • 条件码寄存器大多数时候是被动改变

特殊的测试指令

cmp和test是唯二可以主动设置条件码寄存器的指令

cmp S1,S2:基于S1-S2的值来设置条件码

test S2,S1:基于S2&S1去设置条件码

二者都需加数据格式后缀

访问条件码寄存器

  • 根据条件码组合,将一个字节设置为0,1
  • 条件跳转到程序的某个其他部分
  • 有条件的传送数据

第一种是直接读取条件码寄存器的值,二三种是直接使用,不会显示的读取条件码寄存器的值

SET指令

将条件码组合的值设置到指定的目的操作数,目的操作数只能是单字节的寄存器或储存器中单字节的位置

跳转指令

直接将程序跳转到指定位置,或者根据条件码寄存器的组合进行条件跳转。除了第一个jmp直接跳转指令以及第二个jmp间接跳转指令之外,剩下的12个都是条件跳转指令。

总的来说,跳转指令包含给出一个偏移量和给出绝对地址两种

流程控制

c代码(随便写的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
int jmp(int a,int b)
{
int i;
if(a==b) return a;
for (i=0;i<5;i++)
{
a++;
}
while (b<10)
{
b++;
}
do
{
i++;
}
while (a>=i);
switch (a)
{
case 1:a+=10;
break;
case 2:a+=20;
break;
case 5:a+=30;
break;
}
return a;
}

汇编代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
	.file	"t.c"
.text
.globl jmp
.type jmp, @function
jmp:
.LFB0:
.cfi_startproc
/*if实现判断*/
cmpl %esi, %edi //比较a,b
je .L11 //如果相等,跳到.L11,返回a
movl $0, %edx //如果不相等,进行for循环,把0赋给i
jmp .L3 //跳到.L3
/*if实现判断*/

/*for循环实现*/
.L4:
addl $1, %edi //a自加
addl $1, %edx //i自加
.L3:
cmpl $4, %edx // i和4比较
jle .L4 // i小于或等于4则跳到.L4
jmp .L5 //i大于4则跳到.L5,进行do while循环
/*for循环实现*/

/*do while循环实现*/
.L6:
addl $1, %esi //b自加
.L5:
cmpl $9, %esi //b和9比较
jle .L6 //b小于或等于9,则跳至.L6自加
.L7:
addl $1, %edx //i自加
cmpl %edx, %edi //a和i比较
jge .L7 //a大于或等于i则跳到.L7开头
/*do while循环实现*/

/*switch语句实现*/
cmpl $2, %edi //a和2比较
je .L8 //如果a=2,跳至.L8
cmpl $5, %edi //a和5比较
je .L9 //a=5则跳至.L9
cmpl $1, %edi //a和1比较
je .L14 //a=1则跳至.L14
movl %edi, %eax //取a作为返回值
ret
.L14:
leal 10(%rdi), %eax //计算10+a并作为返回值
ret
.L8:
leal 20(%rdi), %eax //计算20+a作为返回值
ret
.L9:
leal 30(%rdi), %eax //计算30+a作为返回值
ret
.L11:
movl %edi, %eax 取a作为返回值
ret
.cfi_endproc
.LFE0:
.size jmp, .-jmp
.ident "GCC: (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0"
.section .note.GNU-stack,"",@progbits

cmov指令

满足条件的时候进行传送,与set比较像

条件传送指令相当于if-else的赋值判断,一般情况下,比if-else性能好

0%