Tan's Blog.

CSAPP汇编指令2

字数统计: 1.5k阅读时长: 5 min
2019/05/12 Share

计算机系统学习

条件码寄存器

书中列出了四种常用的寄存器,它们的名字与作用分别如下所述。
CF:进位标志寄存器,它记录无符号操作的溢出,当溢出时会被设为1。
ZF:零标志寄存器,当计算结果为0时将会被设为1。
SF:符号标志寄存器,当计算结果为负数时会被设为1。
OF:溢出标志寄存器,当计算结果导致了补码溢出时,会被设为1。
从上面寄存器的简单说明可以看出,ZF和SF可以判断结果的符号,而CF和OF可以判断无符号和补码的溢出。而我们平时使用的高级程序语言,就仅仅靠这四个寄存器,就可以演化出千变万化的流程控制。
几乎所有的算术与逻辑指令都会改变条件码寄存器的值,不过改变的前提是触发了条件码寄存器的条件。比如对于subl %edx,%eax这个减法指令,假设%edx和%eax寄存器的值都为0x10,则两者相减的结果为0,此时ZF寄存器将会被自动设为1。对于其它的指令运算,都是类似的,会根据结果的不同而设置不同的条件码寄存器。

访问条件码

对于普通寄存器来讲,使用的时候一般是直接读取它的值,而对于条件码寄存器来说,则不一定非要读取它的值才能使用。对于条件码寄存器来讲,有三种使用方式,都可以让它发挥作用。
1、可以根据条件码寄存器的某个组合,将一个字节设置为0或1,其实这个就相当于读值。
2、可以直接条件跳转到程序的某个其它的部分。
3、可以有条件的传送数据。
这里面第一种方式其实就是普通寄存器的用法,直接读取条件码寄存器的值,然后进行使用。对于第二和第三种来说,就不是这样了,它们不会显示的读取条件码寄存器的值,而是直接使用。
本节最难的地方,就在于如何将条件码寄存器的组合与条件联系起来。只要理解了这一点,那么条件码寄存器就算是基本掌握了。对于所有的组合都基于a-b这样的前提,也就是说条件码寄存器的值是经过了一个减运算设置后的值。例如,对于e->ZF这样的形式,代表的意思是字母e作为后缀时,则以ZF的值为1视为条件成立。

组合功能
e->ZF相等
ne->~ZF不相等
s->SF负数
ns->~SF非负数
l->SF^OF有符号的小于
le->(SF^OF)或ZF有符号的小于等于
g->~(SF^OF)&~ZF有符号的大于
ge->~(SF^OF)有符号的大于等于
b->CF无符号的小于
be->CF或ZF无符号的小于等于
a->~CF&~ZF无符号的大于
ae->~CF无符号的大于等于

跳转指令

这个指令是我们程序实现流程控制的关键指令,它可以直接将程序跳转到指定的位置,又或者根据条件码寄存器的组合进行条件跳转。总的来说,跳转指令的地址编码一般有两种,第一种是基于PC的,第二种则是绝对地址。基于PC(程序计数器)是指给出一个偏移量,这个偏移量基于当前下一条指令的地址,也就是PC当中的值,这是一种最常用的方式。

1
2
3
4
5
3: eb 03         jmp 8 <loop+0x8>
5: 48 d1 f8 sar %rax
8:
b: 7f f8 jg 5 <loop+0x5>
d: f3 c3 repz retq

对于3处字节编码的第二个字节为03,把它加上0x5,就是下一条指令的地址。而对于b处字节编码的第二个字节为f8,补码转换为10进制-8,加上0xd,得到0x5.
跳转指令一个最大的应用就是可以实现条件分支,一种是通过条件控制来实现,简单理解是先判断再执行;另一种是通过条件传送来实现,先执行再判断。这两种实现方式各有利弊,要根据实际的应用来判断使用哪一个更好。

循环指令

循环指令一般有三种do-while、while和for。
do-while
这个循环结构是先执行循环体的内容,然后再进行判断条件,成立继续循环,不成立就跳出。在汇编中可以使用cmp+label来模拟这个过程。
while
这个循环结构是先判断条件是否成立,然后才进入循环体。在汇编中一种是执行一个无条件跳转到循环结尾处,以此来执行初始的测试。另一种是先进行判断,然后就是do-while的过程。
for
for循环结构其实完全可以沿用while循环的方法,只需要把for的各个条件匹配到while中即可。

switch语句

我平时在程序中很少使用到switch分支语句,它适用于那种对变量进行很密集的判断,这个最好的应用大概就是分别指令集了吧。switch语句的实现很简单,可以用多重if-else来理解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    movl    8(%ebp), %eax//取a
cmpl $10, %eax//比较a和10
je .L10//如果a等于10,跳到.L10进行a=a+10的操作
cmpl $20, %eax//比较a和20
je .L11//如果a等于20,跳到.L11进行a=a+20的操作
jmp .L14//如果a不等于10也不等于20,则跳到.L14进行a=a+30的操作
.L10:
addl $10, 8(%ebp)//a=a+10
jmp .L12//break
.L11:
addl $20, 8(%ebp)//a=a+20
jmp .L12//break
.L14:
addl $30, 8(%ebp)//a=a+30
.L12:
movl 12(%ebp), %eax//取b
movl 8(%ebp), %edx//取a
leal (%edx,%eax), %eax//计算a+b并作为返回值
/* switch语句实现 */

CATALOG
  1. 1. 计算机系统学习
    1. 1.1. 条件码寄存器
    2. 1.2. 访问条件码
    3. 1.3. 跳转指令
    4. 1.4. 循环指令
    5. 1.5. switch语句