前言
本文是一篇对在学习中一些易错和难理解知识点的解释和汇总的博文,因此不会将所有的知识点列出(如易理解的知识点)
第二章计算机运算基础
为什么补码范围是-128~127
课本上肯定和我们说过补码在正数上与原码相同,对于负数,是对原码除了符号位以外,其余位取反之后的值加一。而这本质上就是用0 减去其绝对值的原码就得到其负数的补码了。如
5 : 00000101
-5 : 0000 0000 - 00000101 = 11011 与 10001011 按照定义操作得到的结果是一样的
那么对于-128 我们得到128的原码为:10000000
(在原码中是-0的原码) 那么我们用0 减去 原码得到:10000000
我们惊人的发现和原来的原码是一样的。(我们无法用定义的方式得到),因此可以说这个比原码多出的一个范围,是将原码中0的两种形式中负数的形式的意义变成了-128.好了到了这里你应该明白了把。
为什么减法可以看出是对减数取负之后的加法
我们对于一个减式 X - Y
,我们等价变成X + 0 - Y
,由于具有结合性,那么0 - Y
不就是我们上面所说的Y的取负操作后的值嘛。因此这就得到了解释。
第三章微型计算机结构
寻址方式中哪几种是存储器操作数
分别是
存储器寻址方式:( 直接寻址方式,寄存器间接寻址方式,变址和基址寻址方式,基址变址寻址方式)。它们有一个共同的特点就是操作数中含有[]
符号。了解好这个在后面的章节能更好的理解指令运用的限制。
段寄存器都能存放指令和数据嘛?
- (段寄存器)程序指令的所有指令都在代码段中(CS),其余的不能存放指令。
- 段寄存器)程序运行所使用的数据都可以放在四个代码段的任意一个。存数据一般在隐含段(若不是,则需要显示指明)
为什么说SP中所含的偏移地址是堆栈段中的偏移地址
虽然寻址方式中(不涉及夸段)没有用到SP,但是SP是堆栈指针
。它的内容是PUSH和POP指令或调用等指令从堆栈段中存取栈顶单元信息的
偏移量。因此可以说SP中所含的地址是堆栈中的偏移地址。
在求解存储器操作数的有效地址和实际地址有哪些注意事项
一般的步骤如下,
- 判断出隐含寻址段的类型。(段的基址)。一般除使用BP做基址寄存器的指令是堆栈段(SS)外,其余情况下,均为DS。这个在没有涉及段跨越的时候,如果有,就是跨越段。
- 判断寻址的方式。
- 求出有效地址(偏移量)
- 通过段基址 + 偏移量 得到实际地址。在这一步注意,段基址要先向左移4个二进制位再相加。
第四章汇编语言
判断哪些数据是非法的(重要)
- 第一个是不能出现不是该进制下出现的字符。如8进制,数字只能是0–7,那么就不能出现8,9这两个数字。
- 对于16进制来说,如果首部是字母,则需要在前边添加一个0.这是为了避免与标识符冲突。如
A45H
要写成0A45H
- 最关键的是在表达式中,在书本上的定义为:用运算符号将常数,标识符号等连接起来且有正确数学意义的式子。这里常考两个点,一个是表达式中的常数和标识符号,这里的常数是指数字和ASCII字符,标识符号是用符号定义或等号定义伪指令定义的标识符号。因此对于寄存器这样的就不允许,如
AL + 4
,AL非法的。 另一个考点是运算符,运算符只能是算数运算符,逻辑运算符,关系运算符,分析运算符,组合运算符和记录运算符。如下图,其余的均非法,如101B MUL 0ABH
字符以及字符串都可以如何存储?
除DB以外的伪指令最多定义二个字符的字符串,且按逆序存放在低地址开始单元,如
DW 'AB' 可以
DW 'AFDV' 就不可以。
数据的存储的位置
因为一个单元最多是一个字节也就8位,如果是连续的分开的,就会按顺序右低到高。如DATA DW 10,20,30
就会变成如下图,注意代码中是10进制,会转化为16进制表示,同时由于存储时字类型的因此为在前边自动补0
同时在这个图我们也可以知道,低字节存放在低地址中,同时我们在读取的时候也按照这个规则,先将第一个读到的放入低字节,再往下移动。
什么时候需要指定位数
指令中,如果有 AX、AL…等等寄存器,位数,就是已经给出了。
指令中,如果只有 存储器操作数或者寄存器操作数 和《立即数》,位数,就是不明确。需要指定。
第五章:顺序结构程序设计
前言
这一章的知识点非常杂而且多,是一个重点。大部分都会给出解释和说明,对于设定好的就无能为力,只能死记了。
常见指令的使用限制以及对标志为的影响
数据转送指令
(1)、mov 指令操作
1、CS 不能作为目标操作数。(因为CS的初值不用赋值,不允许转送指令赋值)
2、立即数只能是源操作数(只能给不能要),且不能给段寄存器。
3、存储器,段寄存器(cs除外)和通用寄存器 之间可以两两转送,但除了通用寄存器可以自己到自己之外,其余两个不可以。
4、无影响的状态标志位。
5、两个操作数的位数要一致,
(2)、堆栈操作指令
格式: PUSH src
1、不能是立即数。
2、都没有受影响的状态标志位。
3、PUSH 是先SP指针移动,数据后压位。 POP是先让数据出去,SP指针再后移。
4、字量数据从栈顶压入和弹出时都是低地址字节送低字节,高地址字节送高字节。
5、操作数必须是16位的寄存器操作数(也就是BX,SI,DI)或存储器操作数。
(3)XCHG
1、操作: dest的内容与src的内容互换。
(dest)←→(src)
2、受影响的状态标志位: 没有
3、说明: dest和src不能同时为存储器操作数。段寄存器、立即数不能作为操作数。
XCHG [SI],[BX+10] 不能,因为两个都是关于存储器的寻址方式。
(4)换码指令XLAT
1、指令汇编格式: XLAT
2、操作:BX和AL内容之和指出的内存字节单元
的内容送到AL中。
AL←(BX+AL)
3、受影响的状态标志位: 没有
4、后面不接任何操作数
(5) 地址传送指令
一、取有效地址LEA
注意:
源操作数必须是一个存储器操作数,目标操作数可以是
任一16位通用寄存器、指针寄存器或变址寄存器。(不能是段寄存器)
算术运算指令
所有的加法和减法指令都有如下要求:
dest和src不能同时为存储器操作数和段寄存器。
加法指令
一、加法指令 ADD(Addition) 格式
格式: ADD A,B //A=A+B;
功能: 两数相加
-
OPRD1为任一通用寄存器或存储器操作数,可以是任意一个通用寄存器,而且还可以是任意一个存储器操作数.不能是段寄存器。
OPRD2为立即数,也可以是任意一个通用寄存器操作数.立即数只能用于源操作数B. -
A和B均为寄存器是允许的,一个为寄存器而另一个为存储器也是允许的, 但不允许两个都是存储器操作数.
-
ADD (addition)加法
-
ADC(addition with carry)带进位加
-
INC(increment by 1)增1 : 无论操作数如何,都不会影响CF
要明确操作数的类型
如 INC [BX] 是错的,因为不知道 BX这个位置的数是什么类型的,可以加上强制类型转换。 -
位数要相同。如下
ADD [si],100 指令是错的
原因:
80x86 CPU,它既可以进行 8 位数的运算,也可以进行 16 位数的运算。
你不写清楚位数,就是错的。
- 段寄存器不可在算术指令中
add ds,ax 错
add ax,ds 错
sub ds,ax 错
sub ax,ds 错
减法运算指令
- SUB (subtract)减法
- SBB(subtract with borrow)带借位减
- DEC(decrement by 1)减1 : DEC指令不影响CF
- NEG(negate)取补
- CMP(compare)比较 : CMP 将两个操作数相减,两个操作数保持原值不变,但与SUB指令一样影响标志。
乘法和除法指令
- 操作数都不能是立即数
移位运算的注意事项
- 移动的位数如果只是1,可以是立即数1 ,但是如果大于一·,则不能直接使用立即数,而是先将立即数放入CL 中,之后再
SHR CX,CL
立即数不能做目标操作数原因
如 NEG 30H ; XOR 38H,AL ; NOT 6/H
因为这些操作进行后会将结果放入目标操作数中,而立即数无法存储。
PUSH 和 POP指令的注意事项
- 问操作后栈顶的物理地址与栈顶指针是等价的。
- 栈顶所在的地址是最大的,因此PUSH 后往上移,地址是减小的。
- 对于PUSH 的 -2 ,和 POP 的 +2 ,都是16进制下的加,减法。如SP的值为100H,那么PUSH 操作后,就变成了 00FEH
汇编语言中数据是有无符号的区分
首先需要知道,计算机对数值的存储采用补码形式存储,一来避免了+0和-0的尴尬,二来数值的加法和减法可以统一为补码的加法。
在汇编语言层面,定义变量的时候,没有 signed和unsignde 之分,汇编器统统将你输入的整数字面量当作有符号数(最高位的符号位根据输入的数值符号决定)处理成二进制补码存入到计算机中,只有这一个标准!
汇编器不会区分有符号还是无符号然后用两个标准来处理,它统统当作有符号的!并且统统汇编成补码,这取决于人的使用即主观作用。因此对于最高位是符号位还是还是数值为,是人在使用的时候自己去注意的。
指令对标示位 CF 和 SF 的影响
- CF 是进位标志,SF是符号标识位。
- 对于CF我们就是看在加法中是否最高位有进位,或者在减法的时候最高位是否有借位。
- 对于SF,有个很好的办法就是,最高位的符号是什么SF的值就是什么。
NEG (取补)操作对CF影响的解释
定义是说,如果操作数非0,则操作后CF置0,;否则置1.
- 我们知道对于取补操作而言只有为0的时候,取补后加1才能出现进位,而定义这么说,我们只能记成与常规的不同就好了。
指令对标示位 CF 和 OF 的影响
- OF是溢出标示位。
- 溢出的概念是,如果两个操作数的最高位的相同的数进行相加,如果结果的最高位与原来的不同就是溢出。
- 注意只有当是
正 - 负
和负 - 正
两种情况的时候我们才考虑溢出,否则都不溢出。对于减法(我们直接相减),我们有一个技巧是,如果结果的最高位与减数的最高位不同,则OF为0;相同则是1. 因为对于减法,溢出就只有两种情况,一个是正 - 负
,如果溢出则是正数溢出,结果是的最高位应该是变成负数的标识1,与减数的最高位1相同。另一种情况是负 - 正
,如果溢出则是负数溢出,结果是的最高位应该是变成正数的标识0,与减数的最高位0相同。因此我们对其总结就得到了规律。 - 对于加法,我们就可以按溢出的定义出发就可以了。
很细节就是我们对于有符号和无符号的只是我们人为区分罢了。如一个BYTE位的减法85H - 32H
就是1000 0101 - 0011 0010 = 0101 0011
由上面规律我们知道OF = 1
,但是我们换换觉得这不应该溢出呀,其实不然我们如果看成无符号肯定没有溢出,但是机器只知道这是有符号的,且是补码,那么1000 0101
其实是原码1111 1011
的补码,我们看到这个原码就知道为什么是溢出了吧。如果我们看成是无符号的也没有关系,结果是对的,不过OF
的值是1是无疑的,只不过当认为是无符号的时候,OF的值我们不去关注,或者说没有意义罢了。
NEG指令对OF的影响
经过一番学习,总结得到,NEG
是求原数的相反数,对于有符号数,正数和负数之间只有一个数在1范围内没有相反数,如对于8位,就是-128 ,因此只有当求 对-128进行NEG的时候,OF 置1其余都是0.那么我们就可以得到,只有当有符号数的最小值进行NEG
操作时,OF 才为1 ,其余数操作后OF 都是0.
无符号,有符号乘法和除法的注意事项
- AL * BL ,AL / BL ,等暂称为等字节的两个操作数。
- 对于无符号,如果两个操作数,等字节,那么我们需要用 XOR 符号,将高位清0
- 对于有符号来说,则是用 CBW ,目的是为了确保结果符号的正确性。
加减乘除操作的注意事项
ADC (带进位加法的妙用)
- 对于ADC我们常用在,对于可能溢出的加法操作,我们利用ADC将进位放到高位中去。如
ADC DX , 0
乘法
因为乘法的两个运算指令都是对位数相同的两个数进行操作。
因此对于位数不同操作的时候,
- 无符号乘法: 我们需要将低位数的进行拓展为高位,同时为了不影响结果,因此我们需要将低位数的值的高位清零。使用 异或 , 如
AH XOR AH
- 对于有符号乘法: 也是同理的不过,对于有符号的有指定的命令, 分别是
CBW
用于将低位数是8位的,在拓展为16位的时候使用。同理CWD
是16 --> 32
除法
因为除法原本是高位数除以低位数的。那么当变成同位数的两个数相除的时候,我们这个时候,就需要对被除数进行位数拓展。与上面乘法类似。