(学习笔记)3.6 控制(3.6.1 条件码& 3.6.2 访问条件码)

AI4天前发布 beixibaobao
5 0 0

文章目录

  • 线索栏
  • 笔记栏
    • 1. 控制流基础
      • 1)目标
      • 2)机器级机制
    • 2. 条件码寄存器
      • 设置规则
    • 3. 比较与测试指令 (CMP & TEST)
    • 4. 访问条件码:SET指令
      • 1)指令格式
      • 2)关键后缀规律
      • 3)同义名
      • 4)SET指令表(图3-14)要点
    • 5. 代码示例:comp函数
      • 关键步骤
    • 6. 练习题
      • 练习题3.13
      • 练习题3.14
  • 总结栏

线索栏

  1. 核心机制:机器代码如何实现C语言中的条件控制(如if、while)?
  2. 条件码:CPU维护了哪几个单比特的条件码寄存器?ADD指令执行后,它们如何被设置?(以t = a + b为例)
  3. 专用指令:除了算术/逻辑指令,哪两条指令只设置条件码而不改变目的寄存器?它们分别基于什么操作?
  4. SET指令:访问条件码的第一种方式是什么?SET指令的目的操作数是什么大小?
  5. 命名与规律:如何从SET指令的后缀(如l, b, e, ne)判断它用于有符号比较还是无符号比较?setg和 setnle是什么关系?
  6. 代码生成:编译器如何生成指令序列来计算表达式 a < b?(以comp函数为例,结合CMP、SET、MOVZ指令
  7. 类型推导:如何根据给定的CMP/TEST和SET指令序列,反向推断出源代码中数据的类型(int?unsigned long?)和比较操作(<?>=?)?(练习题3.13, 3.14)

笔记栏

1. 控制流基础

1)目标

实现C语言的条件语句、循环等。

2)机器级机制

(1)测试数据:通过运算设置条件码(Condition Codes)。
(2)改变控制流:根据条件码,通过JUMP指令跳转到代码的不同部分。

2. 条件码寄存器

CPU维护一组单比特寄存器,描述最近一次算术/逻辑运算的属性:

条件码 名称 触发条件 (以 t = a + b为例) 解释
CF​ 进位标志 (unsigned)t < (unsigned)a 无符号溢出(最高位进位)
ZF​ 零标志 (t == 0) 结果为0
SF​ 符号标志 (t < 0) 结果为负数(符号位为1)
OF​ 溢出标志 (a<0 == b<0) && (t<0 != a<0) 有符号溢出

设置规则

(1)LEA指令不改变条件码。
(2)图3-10中大多数指令(ADD, SUB, INC, DEC, 位运算等)都会设置条件码。
(3)移位操作:CF= 最后移出的位;OF=0。

3. 比较与测试指令 (CMP & TEST)

这两条指令只设置条件码,不改变目的寄存器。

在这里插入图片描述

指令类 行为 (ATT格式) 描述
CMP S1, S2​ 计算 S2 – S1, 据此设置条件码 比较。操作数顺序与SUB相反 (CMP b, a比较 a和 b)。
TEST S1, S2​ 计算 S1 & S2, 据此设置条件码 测试(通常用于检查位或是否为0)。

4. 访问条件码:SET指令

SET指令根据条件码的某种组合,将一个字节(Byte)​ 设置为0或1,这是访问条件码的第一种方式。

1)指令格式

setX D, 其中X是表示条件组合的后缀,D是单字节寄存器(如%al)或内存地址。

2)关键后缀规律

(1)用于有符号比较:g(greater), l(less), e(equal)等。
(2)用于无符号比较:a(above), b(below), e(equal)等。

3)同义名

同一条机器指令可能有多个名字(如setg≡ setnle)。

4)SET指令表(图3-14)要点

在这里插入图片描述

5. 代码示例:comp函数

int comp(data_t a, data_t b) { return a < b; }
// a in %rdi, b in %rsi
comp:
    cmpq  %rsi, %rdi   # 比较 a 和 b (计算 a - b)
    setl  %al          # 若 a < b (有符号),则 %al = 1,否则为0
    movzbl %al, %eax   # 零扩展%al到%eax (同时清零高4字节)
    ret

关键步骤

CMP→ SET→ MOVZ扩展。

6. 练习题

练习题3.13

在这里插入图片描述

根据指令序列推断data_t和COMP。
A. cmpl %esi, %di; setl %al
cmpl:操作双字(4字节)→ data_t= int。
setl:有符号小于 → COMP= <。

B. cmpw %si, %di; setge %al
cmpw:操作字(2字节)→ data_t= short。
setge:有符号大于等于 → COMP= >=。

C. cmpb %sil, %dil; setbe %al
cmpb:操作字节(1字节)→ data_t= char。
setbe:无符号低于等于 → COMP= <=(无符号)。

D. cmpq %rsi, %rdi; setne %al
cmpq:操作四字(8字节)→ data_t= long或 unsigned long或指针。
setne:不等于(不区分符号)→ COMP= !=。

在这里插入图片描述

练习题3.14

在这里插入图片描述


根据TEST和SET推断data_t和TEST。TEST a, a用于测试a本身。
A. testq %rdi, %rdi; setge %al
testq:测试8字节 → data_t= long。
setge:有符号非负 → TEST= >=0。

B. testw %di, %di; sete %al
testw:测试2字节 → data_t= short。
sete:等于0 → TEST= ==0。

C. testb %dil, %dil; seta %al
testb:测试1字节 → data_t= char或 unsigned char。
seta:无符号大于 → 在TEST后,a>0等价于 a != 0→ TEST= !=0(但更准确是>0,对无符号数两者等价)。

D. testl %edi, %edi; setne %al
testl:测试4字节 → data_t= int。
setne:不等于0 → TEST= !=0。

在这里插入图片描述


总结栏

本节是理解机器级控制流的基石,引入了条件码系统及如何通过SET指令将其转换为布尔值。

  1. 条件码是状态记录器:CF, ZF, SF,OF四个标志位记录了上一次算术/逻辑运算的关键副作用(溢出、零、符号)。CMP和TEST是专门为比较测试而设、不修改操作数的指令。
  2. SET指令是转换器:它将条件码的复杂组合(如图3-14中的SF^OF)转换为一个简单的布尔值(0或1),存入一个字节。这是实现C语言关系表达式(如a<b)返回值的关键步骤。
  3. 机器不区分类型,但指令选择体现语义:CPU执行相同的CMP指令,但根据后续SET指令的不同后缀(lvsb)来决定进行有符号还是无符号比较。这是理解汇编代码中数据类型信息的关键。
  4. 规律性:SET指令的后缀命名具有规律:l/g系列用于有符号,a/b系列用于无符号。e/ne通用。条件组合基于CMP a,b(计算a-b)的结果。
  5. 逆向工程训练:练习题3.13和3.14强化了从指令序列到高级语言结构的反向推理能力。需综合指令后缀(b/w/l/q)→数据类型大小、SET后缀(l/b/a/g…)→ 比较类型和符号性两条线索。

核心启示:计算机通过“先计算状态,后查询状态做出决策”来实现条件分支。条件码系统是这一“状态”的标准化、硬件化的表示。SET指令是连接底层状态与高层逻辑判断的桥梁。掌握条件码和SET指令,是理解后续JUMP(条件跳转)和CMOV(条件传送)指令的基础。

© 版权声明

相关文章