最近在啃汇编,一大堆的理论知识,感觉挺枯燥的,经常看书看着看着就睡着了😂,现在把一些重要知识点汇总一下
# 字符表示
计算机中的数用二进制表示,数的符号也是用二进制表示,一般数的最高有效位用来表示数的符号,正数为 0,负数为 1,常用的有原码、反码、补码这三种表示,目前计算机基本只采用补码的方式表示
- 原码
以机器字长 8 位为例: +10D 的原码表示为 0000 1010, -10D 的原码表示为 1000 1010,原码不能直接参与运算,因为高位的符号位会导致运算结果出错
例如 (+1D) - (+1D)
在计算机中会转换成 (+1D) + (-1D)
, 用原码表示为 0000 0001 + 1000 0001 = 1000 0010
, 运算结果为 -2D,这个结果明显是错误的
计算机中只有加法器,没有减法器,这是因为减法运算中有一条法则,就是一个数减去另一个数等于加上另一个数的相反数,所以加法器可以同时实现加法和减法的运算,为了简化电路的复杂度,计算机便舍弃了减法器
- 反码
反码是原码转换补码的一种过渡码,它将原码按位求反,得到的结果即这个数的反码
以机器字长 8 位为例:
+10D 的原码表示为 0000 1010,反码表示为 0000 1010
-10D 的原码表示为 1000 1010,反码表示为 1111 0101
正数的反码、补码和原码一样,负数最高有效位不变,其它位求反
- 补码
补码是在反码的基础上末位 +1 得到这个数的补码
以机器字长 8 位为例:
+10D 的原码表示为 0000 1010, 补码表示为 0000 1010
-10D 的原码表示为 1000 1010,补码表示为 1111 0110
补码的出现就是为了实现计算机减法运算的问题
例如 (+1D) - (+1D)
在计算机中会转换成 (+1D) + (-1D)
, 用补码表示为 0000 0001 + 1111 1111 = 1 0000 0000
, 由于机器字长为 8 位,最高位的 1 会被计算机舍弃掉,结果为 0000 0000
我们可以通过代码来验证 +1D 和 -1D 在计算机内存中表示的数据是不是 0000 0001
和 1111 1111
# 寄存器
80x86 CUP 一共有 14 个 16 位寄存器,它们分别是 AX、BX、CX、DX、SP、BP、SI、DI、DS、ES、SS、CS、IP、FLAGS,我觉得其它的寄存器还是比较容易理解的,就是 FLAGS 寄存器有点难记忆
其中 AX、BX、CX、DX 为数据寄存器,并且这四个数据寄存器都可以拆分成 2 个独立的 8 位寄存器
16 位 | 高 8 位 | 低 8 位 |
---|---|---|
AX | AH | AL |
BX | BH | BL |
CX | CH | CL |
DX | DH | DL |
SP 和 BP 是指针寄存器,SP 是堆栈指针,BP 是基址指针
SI 和 DI 是变址寄存器,SI 是源地址寄存器,DI 是目的地址寄存器
DS、ES、SS、CS 是段寄存器,DS 是数据段寄存器,ES 是附加段寄存器,SS 是堆栈寄存器,CS 是代码段寄存器
IP 是指令指针寄存器
FLAGS 是标志寄存器,FLAGS 寄存器一共有 9 种标志,其中 1、3、5、12、13、14、15 位并没有使用,FLAGS 寄存器主要用于反映处理器的状态和处理结果的某些特征
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
OF | DF | IF | TF | SF | ZF | AF | PF | CF |
标志名 | 标志为 1 | 标志为 0 |
---|---|---|
OF 溢出 (是 / 否) | OV (over flow) | NV (not over) |
DF 方向 (减少 / 增加) | DN (down) | UP (up) |
IF 中断 (允许 / 关闭) | EI (enable interrupt) | DI (disable interrupt) |
SF 符号 (负 / 正) | NG (negative) | PL (plus) |
ZF 零 (是 / 否) | ZR (zero) | NZ (not zero) |
AF 辅助进位 (是 / 否) | AC (auxiliary carry) | NA (not auxiliary carry) |
PF 奇偶 (偶 / 奇) | PE (parity even) | PO (parity odd) |
CF 进位 (是 / 否) | CY (carry) | NC (not carry) |
- OF(overflow flag)
溢出标志,在有符号数值运算过程中,如果操作数超出了机器能表示的范围,OF 标志为 1,否则为 0,溢出标志只对有符号数值运算结果有影响
打开 Debug 测试验证,AL = 49H,BL = 64H,AL + BL = ADH,ADH = 1010 1101B = (173D),在机器字长 8 位的寄存器中,有符号数值取值范围为 -128 ~ 127,其结果造成了溢出,所以这里的 CF 标记为 OV,如果是无符号数值运算,这个结果则是正确的
我刚开始接触 OF 标志时,其实我是有点疑惑的,为什么这里结果是按照有符号数运算,我在网上搜了一下,并没有找到我满意的答案,只好自己通过大量的数值进行测试,最后终于解开了这个疑惑,可以看一下我下面的两段代码的结果,它们的结果都是 ADH,一个溢出了,一个没有溢出,思考一下这是为什么
- DF(direction flag)
方向标志,在串处理指令种控制处理信息的方向,当 DF 位为 1 时,每次操作后使 SI 和 DI 值减少,这样串处理便从高地址向低地址的方向处理,当 DF 位为 0 时,每次操作后使 SI 和 DI 值增加,这样串处理便从低地址向高地址的方向处理
- IF(interrupt flag)
中断标志,当 IF 位为 1 时,CPU 响应可屏蔽中断请求,否则关闭中断
- TF(trap flag)
跟踪标志,用于调试时的单步操作,当 TF 位为 1 时,每条指令执行完后产生中断,由系统控制计算机,当 TF 位为 0 时,CPU 正常工作,不产生中断
- SF(sign flag)
符号标志,记录运算结果,与运算结果的最高位相同,运算结果最高位为 1,SF 标志为 1,否则为 0
- ZF(zero flag)
零标志,运算结果为 0 时,ZF 位为 1,否则为 0
- AF(auxiliary carry flag)
辅助进位标志,在字节操作时,低半字节 (第 3 个字节) 向高半字节 (第 4 个字节) 进位或者借位,在字操作时,低字节 (第 7 个字节) 向高字节 (第 8 个字节) 进位或者借位,有进位或借位时 AF 位为 1,否则为 0
- PF(parity flag)
奇偶标志,用于反馈运算结果中 1 的个数,当结果操作数中低 8 位 1 的个数为偶数时 PF 位为 1,否则为 0
在 debug 中分别测试一下 1,2,3,0 四个数值 PF 标志的变化
- CF(carry flag)
进位标志,记录运算时从最高有效位产生的进位值,例如执行加法指令时最高有效位有进位时 CF 位为 1,否则为 0