前言
在持续输出ing
一、条件码
1.处理器状态(x86-64,部分的)
- 当前程序的执行信息
◼ 临时数据
◼ 运行时栈的位置(栈顶)
◼ 当前代码控制点的位置(即将要执行的指令地址)
◼ 最近一次指令执行的状态

2.条件码(隐式设置)
- 简单的位寄存器
条件码(隐式设置)
CF 进位标志(无符号数)
SF 符号标志(有符号数)
ZF 零标志
OF 溢出标志(有符号数) - 通过算术运算可以隐式设置条件码(可以把它看做是运算的副作用)
◼ 例如: addq Src,Dest ↔ t = a+b
◼ CF 被置位,如果运算时出现了超出最高位的进位(无符号数运算溢出)
◼ ZF 被置位,如果 t ==0
◼ SF 被置位,如果 t<0 (看做是有符号数)
◼ OF 被置位,如果有符号数运算出现了溢出
(a>0 && b>0 && t<0) || (a<0 && b<0 && t>=0)
3.条件码(显式设置:比较指令)
- 通过比较指令可以显式设置条件码
Explicit Setting by Compare Instruction - cmpq Src2, Src1
- cmpq b,a 这条指令和a-b的作用类似,但不需要将结果写入目标寄存器
◼ CF 被置位,如果运算时出现了超出最高位的借位(用于无符号数比较)
◼ ZF 被置位,如果 a == b
◼ SF 被置位,如果 (a-b) < 0 (看做是有符号数)
◼ OF 被置位,如果有符号数运算出现了溢出
(a>0 && b<0 && (a-b)<0) || (a<0 && b>0 && (a-b)>0)
3.条件码(显式设置:测试指令)
- 通过测试指令也可以显式设置条件码
- testq Src2, Src1
◼ testq b,a 这条指令和a&b的作用类似,但不需要将结果写入目标寄存器
◼ 根据 Src1&Src2 的结果设置条件码
◼ 用于对一个操作数的某几个位进行掩码检测
◼ ZF 被置位,当 a&b == 0
◼ SF 被置位,如果 (a&b) < 0
4.读取条件码
- SetX指令
◼ 根据条件码表达式将目标寄存器的最后一个字节修改为0或1
◼ 不会影响目标寄存器最高7个字节的值
5.x86-64 各寄存器中最后一个字节的名称

6.读取条件码
- 在x86-64指令集中,32位操作指令 会将目标寄存器的高32位清0

二、条件分支
1.跳转
- jX指令
◼根据条件码跳转到代码的其他位置执行


这是机器指令与汇编代码的对应

- 生成汇编代码
gcc –Og -S –fno-if-conversion control.c
2.使用goto语句等价表示
- 语言允许使用goto语句
◼ 跳转至标签所在位置的语句继续执行


3.条件表达式的翻译(使用分支)
- 为Then和Else表达式创建独立的代码块
- 根据条件选择合适的一个代码块并执行



4. 使用条件数据移动指令
- 条件数据移动指令
◼ 指令的功能:if (Test) Dest Src
◼ 1995年后的x86处理器开始支持- GCC在编译时会尝试使用这个指令翻译条件分支
◼ 仅当保证逻辑安全的时候使用
- GCC在编译时会尝试使用这个指令翻译条件分支
- 为什么使用条件数据移动指令?
◼ 分支会破坏流水线的指令流,影像处理器性能
◼ 条件数据移动指令不需要改变控制流


5.流水线
- 最多可以有三条指令同时执行


下面是例子
这是C代码

这是寄存器存储的值


6.不能使用条件数据移动指令的情况
-
大量的计算
◼ 条件数据移动指令会将所有的结果提前计算出来
◼ 只有计算都非常简单的时候,使用条件数据移动指令才会有意义

-
存在风险的计算
◼ 可能导致程序出错

-
有副作用的计算

三、循环
1.Do-While循环
- 计算x编码中“1” 的个数
- 使用条件分支决定继续或退出循环
C代码

goto版本

翻译后
汇编为

寄存器里的值为

Do-While循环通用的翻译方式
-
C代码

-
Goto
-
先执行 如果满足条件继续循环

2.while循环
While循环通用的翻译方式(1)
- “跳转到中间”翻译方法
- 使用 –Og 编译优化选
C代码

可以看到下面汇编代码里面执行到最后
如果满足条件那么就跳转到中间
与 do-while 循环相比,循环开始
前先跳转至循环条件检测的位置(注意第一行 gototest!!!)

While循环通用的翻译方式(2)
dowhile法

先翻译成dowhile

再依据dowhile的版本翻译Goto版本

3.for循环
for循环的通用翻译方式
“For” Loop → While Loop → Goto

while

dowhile

goto

四、switch语句
会考的
以下面的switch语句为例
我们可以看到
- 多个case (5 & 6)共用同一语句块
- Case2贯穿
- Case4缺失(case值不连续)
1.跳转表
- 用作switch语句翻译的一个表
- switch语句的通用翻译如下

注意这个goto 语句 后面接的是跳转表

1.跳转表的结构
- 基地址是 .L4
- 每个跳转目标需要8个字节(指向目标语句块的地址)


- 这是跳转表里跳转目标对应的语句块

2.直接跳转
- jmp .L8
直接跳转至.L8标签所指向地址的指令
3.间接跳转
- jmp *.L4(,%rdi,8)
- 跳转表起始地址.L4(跟那个存储器寻址可以类比一下)
- 缩放因子必须是8的整倍数(每个地址是8个字节)
- 从地址 .L4 + x*8 处获得跳转目标的位置
- 仅限于 0 ≤ x ≤ 6的情况
4.分析跳转表(例子分析)
给一段switch语句

汇编代码为

跳转表如下

- 跳转表与switch语句对应关系如图

(1)正常情况 x==1

对应的汇编代码以及寄存器的值对应如下图


(2)代码块贯穿 x= =2 x= =3(无break)
对应C代码应该为
汇编代码为(可以看到执行完case2就执行case3里面的代码 w+=z)

(3)缺省 x= =5 x= =6(共用一个代码块)

汇编代码也是共用一块


(4)没有从0开始的情况

汇编代码还是会处理成从0开始

(5)稀疏的switch语句

- 将翻译为二分查找的语句 O(log n)
- 而不是退化为 if-elseif-elseif-else O(n)






![[FSCTF 2023]Tea_apk](https://img-blog.csdnimg.cn/img_convert/da6f7905560203ed885bc4bc9166a278.png)




![[大模型]CharacterGLM-6B Transformers部署调用](https://img-blog.csdnimg.cn/direct/176bd95cde044cc88e77d18adc164b9a.png)






![[ROS 系列学习教程] 建模与仿真 - 使用 Arbotix 控制机器人](https://img-blog.csdnimg.cn/direct/5641c37339584af5892f3c95e7919f96.gif#pic_center)

