欢迎光临
我们一直在努力

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

文章目录

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

线索栏

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

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

    赞(0)
    未经允许不得转载:171主机测评 » (学习笔记)3.6 控制(3.6.1 条件码& 3.6.2 访问条件码)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址