CSAPP第三章之条件码、跳转指令

控制

机器代码提供

  1. 测试数据值
  2. 根据测试结果改变控制流

条件码

CPU维护着一组条件码寄存器

  1. CF:进位标志。可以检查无符号操作的溢出。
  2. ZF:0标志
  3. SF:符号标志。最近的操作结果为负数。
  4. OF:溢出标志。检查有符号操作的溢出。

leaq不改变任何条件码——它是用来进行地址计算的
除此之外,加法、乘法、移位、逻辑运算等指令都会设置条件码
逻辑操作会将进位标志CF与溢出标志OF设为0
移位操作会将进位标志CF设为最后溢出的位,溢出标志OF设为0
INC与DEC只会设置溢出标志与零标志,不会改变进位标志

特殊的指令——只改变条件码,不改变整数寄存器

  1. CMP
  2. TEST
    二者均是二元操作,且每类都有4个分支

CMP执行的操作:CMP S1 S2,比较S2-S1(相当于SUB,但是不设置寄存器)
TEST执行的操作:TEST S1 S2,比较S1&S2(相当于AND,但是不设置寄存器)

访问条件码

条件码不会直接读取,常用的使用方法

  1. 根据条件码的某些组合,将一个字节设置为0或者1(SET类指令)
  2. 条件跳转到程序的其它部分
  3. 条件传输数据

SET类指令:区别在于考虑的条件码的组合——后缀表明了考虑的条件码的组合,而非操作数大小
例如setl:小于xx的时候设置(有符号),setb:低于xx时设置(无符号)

movzbl不仅会将%eax的高三个字节清零,还会将整个寄存器%rax清零

// 因为觉得自己完全没用可能记得住那么多,所以也不打算看完
// 等到需要用的时候再用就行了

跳转指令

跳转指令的目的地使用一个label(标号)表明
例如.L1就是一个标号

跳转指令jmp是无条件跳转,既可以直接把跳转目标编写到指令中,也可从寄存器或者内存中读取跳转目的
直接跳转:.L1
间接跳转:在*后面跟上一个操作数提示符

// 因为觉得自己完全没用可能记得住那么多,所以也不打算看完
// 等到需要用的时候再用就行了

跳转指令的编码

理解跳转指令的目标如何编码,对于研究链接很重要

跳转指令有几种不同的编码,但是最常用的都是PC-relative
即将目标指令的地址,与紧跟着跳转指令后面的指令的地址的差,作为编码
这些地址的偏移量可以是1、2、4个字节
举例:

movq %rdi, %rax
jmp .L2
.L3
sarq %rax
.L2
testq %rax, %rax
jg .L3
rep; ret

使用反汇编器反汇编的结果

0: 48 89 f8		mov	%rdi, %rax
3: eb 03		jmp	8<loop+0x8>
5: 48 d11 f8	sar	%rax
8: 48 85 c0		test	%rax, %rax
b: 7f f8		jg	5<loop+0x5>
d: f3 c3		repz retq

第一条跳转指令的目标编码为0x03,加上0x05后就是下一条指令的位置
第二条跳转指令的目标编码为0xf8,加上0x0d13 - 8f8为十进制-8)为0x05
使用相对寻址时,PC计数器的值是跳转指令后的指令的地址,而不是跳转指令本身的地址*【

在使用链接器链接之后,地址跳转的指令并不会发生改变

  • 小贴士:reprepz的区别
    repzrep的同义名,retpret的同义名
    它们通常用来实现重复的字符串操作
    rep后面跟上ret避免ret指令称为条件跳转指令的目标,这里的rep就是一个空操作,除了提高程序的运算速度之外没有其它操作。

第二种编码方式,是给出绝对地址,使用四个字节直接指定目标。

这两种跳转方式,编译器会使用最合适的方式进行编写

上一篇:csapp malloclab


下一篇:《深入理解计算机系统》(CSAPP)读书笔记 —— 第一章 计算机系统漫游