第1-2课:第一次上机
汇编语言的学习相较于c语言这类高级语言来说入门更难,所以学会汇编语言一定会成为你的助力,学习计算机语言从实际操作入手更能让人接受,所以第一次先从上机开始,汇编语言中的字符大小写均可。
以下//表示注释,不在源代码中
学习准备:汇编系统MASM和DOSBox
学习目标:输出hello,和5+3结果
操作流程:打开DOSBox,输入
mount c: c:\masm
这条语句表示把c盘的这个文件夹映射到c盘目录(masm为你下载后的文件,可自己命名,可以是c盘也能是别的盘,存在什么盘就用什么字母)
出现该语句即为映射成功
c:
切换至c盘目录
edit yy2.asm
编辑该文件,注意后缀名要为asm,文件名自定义
这时会弹出蓝色框框
data segment
a db 'Hello!$'//字符串结尾用$
data ends
code segment
assume cs:code, ds:data
start: mov ax,data
mov ds,ax
lea dx, a
mov ah,9
int 21h
mov ah,4ch
int 21h
code ends
end start
DATA SEGMENT
A DB 3
B DB 5
C DB ?
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START:MOV AX,DATA
MOV DS,AX
MOV AL,A
ADD AL,B
MOV C,AL
MOV DL,C
OR DL,30H
MOV AH,2
INT 21H
MOV AH,4CH
INT 21H
CODE ENDS
END START
在框框内编辑出上面任意一个
点击左上角FILE保存并退出
输入命令
MASM yy2
将文件汇编成目标文件
LINK yy2
将目标文件转化为可执行文件
输出
yy2
2.debug上机操作
命令:
R命令作用:观看和修改寄存器的值
H命令作用:计算两个十六进制数的和与差
D命令作用:显示内存区域的内容
E命令作用:改变内存单位的内容
F命令作用:使用指定的值填充指定内存区域中的地址
M命令作用:将指定内存区域的数据复制到指定的地址去
C命令作用:将两块内存的内容进行比较
S命令作用:在指定的内存区域中搜索指定的串
A命令作用:输入汇编指令
G命令作用:执行汇编指令
U命令作用:对机器代码反汇编显示
N命令作用:设置文件名,为将刚才编写的汇编程序存盘做准备
W命令作用:将文件或者特定扇区写入磁盘
L命令作用:从磁盘中将文件或扇区内容读入内存
T命令作用:执行汇编程序,单步跟踪
P命令作用:执行汇编程序,单步跟踪。与T命令不同的是:P命令不会跟踪进入子程序或软中断
I命令作用:从计算机输入端口读取数据并显示
O命令作用:向计算机输出端口送出数据
Q命令的作用是退出DEBUG,回到DOS状态
常用十六进制
0 - 30H
1 - 31H
A - 41H
a - 61H
空格 - 20H
回车 - 0DH(非数字开头的十六进制数前加0)
换行 - 0AH
启动debug:
打开DOSBOX,输入命令
mount c: c:\masm
c:
debug
出现"-"提示符表示debug启动成功,输入q退出debug,cls清屏
计算两个数的和与差
实现5+3操作
输入d命令和u命令
复制
修改
显示hello
第3-4课:计算机语言及数制相关知识
//注意:以下挨在一起的是指数,中间有空格分开的为一个整体
想要手翻汇编语言成机器语言的老师介绍了一本书,《IBM-PC及长城0520(INTEL8088/8086)宏汇编语言程序设计》
计算机语言的发展和分类
1.机器语言:计算机直接识别和执行的一组二进制序列
2.汇编语言:
pc端汇编(cpu型号发展由8086/8088 —— 80286 —— 80386 —— 80486 —— 80486——奔腾 —— 酷睿系列)目前我们学习的就是8086/8088,这些型号的汇编语言是向上兼容的。
Apple汇编
单片机汇编
3.高级语言:脱离了机型,在任何机型都能运行兼容
4.面向对象的程序设计语言(可视化编程语言):例(Visual C++,VB,VFP)
单位换算公式
1.存储容量换算公式
1GB = 1024MB
1MB = 1024KB
1KB = 1024B
1B = 8个二进制位
1TB = 1024GB
1个汉字占2字节
1个英文字符占1字节
2.cpu主频换算公式
1GHz = 1000MHz
1MHz = 1000KHz
1KHz = 1000Hz
老师分享了一个农行的面试题,如下:
例:某微机cpu为25MHz,执行一条加法指令为5个总线周期,问该cpu每秒钟执行加法的次数?
必知公式:1个总线周期 = 4个时钟周期
答:
- f = 25 MHz
- t = 1 / f = 1 / 25*10^6 (秒) ——时钟周期
- 执行1次加法的时间 = 5*4*4*10^-8 = 8*10^-7秒
- 每秒钟执行加法次数 = 1 / 8*10^-7 = 1.25*10^6 = 1250000次
汇编语言中的进制
1.二进制带尾符B
2.八进制带尾符O
3.十进制带尾符D或缺省
4.十六进制带尾符H
计算:3A2BH - 596CH = ?
竖式计算不够借1,注意最高位如果还需要借只用记作有借位即可
3A2BH - 596CH = E0BFH (cf = 1 表示借1位,显示 cy)错误答案(-20BFH)
DOSBox操作结果如下
Windows操作技巧:Alt + Enter 全屏/窗口的切换
mac为:command+control+f
与或非在这里就不说了,接下来是原码反码补码的转换技巧
1.X=-1 在8位机上的补码为FFH,在16位机上的补码为FFFFH
2.X=-5的补码只要在X=-1的情况下-4就行,所以在8位机上补码为FBH,16位机上补码为FFFBH
3.X=-15 在8位机上的补码为F1H,在16位机的补码上为FFF1H
关于符号,在16位进制中最高位如果大于等于8,那么这个数十进制就为负数,如上述例子都为负数
tips:如果16进制首位为字母则要在前一位加0,但是0并不代表最高位的符号位,如0B256H为负数,但是0968H这里的0就占一位所以这是正数
重要结论:
1.字长n位的机器,表示的有符号整数范围是 -2^n-1 到 +2^n-1 - 1
例:8位机: -128到+127 16位机:-32768到+32767
2.字长n位机器,无符号数表示的整数范围是 0到2^n - 1
第5课:补充
快速解决机器数化十进制真值问题,不需要用补码的逆转换。
思考:知道机器数,如何求十进制表示的真值?
方法:
1.机器数的表示为补码形式,采取补码的逆转换,再由二进制转十进制。
2.如机器数最高位为0,表示正数,直接化二进制为十进制。
3.如机器数最高为1,表示负数,对机器数按位取反(包括符号位),末位加1,再将该二进制转化十进制数,加上负号,即表示十进制真值。
例子:已知某8位机器数为 1000 0000 其 真值用十进制表示为___.
- 1000 0000
- 取反:0111 1111
- 末位加1:1000 0000
- 二进制转十进制:-128
关于计算十六进制乘法的技巧
跟十进制类似,十进制乘法满十进下一位,而十六进制乘法则是看两个数相乘之后能在结果中分出几个十六进到下一位,例如 0EH * 9H ,E为14,相当于14*9=126, 126又相当于16*7+14,所以相乘的结果为7EH。
如何判断溢出?
进位:最高有效位进位才为进位
溢出:超出了表示的范围
老师教了一种不同于书上的判断溢出的方法,更加快速便捷。
结论:运算结果违背常理即溢出
基本定理:
正 + 正 = 负 溢出
正 + 负 不溢出
负+ 负 = 正 溢出
负 - 正 = 正 溢出
负 - 负 不溢出
解释:正和十进制中的加减法一样,一个正数加一个正数一定会是一个正数,所以一旦这个结果是负数,即为违背常理,在十六进制中出现该情况即为溢出,不用转化为二进制再判断。
不多说了,上例子。
1.计算8A36H + 954CH 是否溢出?
结果为1F82H(进位不用理会)因为最高位数字大小小于8所以这是一个正数(这里不懂正负数怎么判断可以看往上滑)而8A36H和954CH均为负数,根据公式负+负=正可知,该结果溢出。在dosbox中运行,OF=1显示OV
2.计算3456H-F76AH 是否溢出?
3456H为正数 F76AH为负数,结果为3CECH 正数-负数=正数符合常理所以该结果不溢出。 在dosbox上,OF=0,显示NV
ASCII码
ASCII码:美国标准信息交换码,是国际上通用的一种字符编码,用低7位二进制数表示1个字符的编码。最高位可用于扩充字符(如中文汉字需要两个字节,所以预留1位和下一字节合并)或用作奇偶效验码。
ASCII码有2^7种排列组合,可表示128个字符。
奇偶效验码定义:让字符编码的最高位在0-1之间变化。
例如A:0100 0001
奇效验码:1100 0001,使得1的个数为奇数
偶效验码:0100 0001,1的个数为偶数
回车符:0DH 光标回到本行起始位置
换行符:0AH 光标跳到下一行该位置
上机计算 7AB * 6F = 35325H
imul表示乘法
t命令运行下一步
DX表示高四位 AX为低四位 CY表示进位
第6课:计算机组织
cpu ⇋ 内存 ⇋ 外存
存储单元的地址和内容:
存储器以字节(8 bit)为编程单位
每个字节单元都有唯一的地址编码
地址用无符号整数来表示(编程用十六进制表示)
一个字要占用相继的两个字节
低位字节存入低地址,高位字节存入高地址
字单元地址用它的低地址来表示
机器以偶地址访问(读 / 写)存储器
逻辑地址:由段地址和偏移地址两部分构成,中间用:隔开。
物理地址:存储单元的实际地址,用20位的二进制表示。
物理地址(PA)=段地址 * 10H + 偏移地址。
逻辑地址只能对应一个物理地址,而一个物理地址可对应多个逻辑地址。
例如:物理地址12345H 对应逻辑地址1234:0005 1230:0045等等
20根地址线:也就是20个二进制位即2^20次方位,即1MB,所以cpu为8086的内存最大只能为1MB。
机器字长16位:指16位二进制,即2^16次方,64KB
(未指定段类型)小段:能被16整除或能被10H整除的即为一个小段,即20位二进制数最后四位为0才是段地址,因物理地址等于段地址*10+偏移地址
段的大小:转化成逻辑地址来理解,例如物理地址00030H,对应逻辑地址为0000:0030若该段大小为64K,则末地址为0030H + FFFFH = 1002FH,而1002FH - 000030 = 0FFFF即为64K,偏移地址4位最大为FFFF最小为0000所以相减即为段的最大大小64K。
计算机第一个运行的程序,引导程序,rom、bios芯片
第7-8节课:寄存器
中央处理器
1)14个寄存器介绍
1. 8个通用寄存器
1* 4个数据寄存器(16位)
AX:累加器(16位),可分为高八位AH和低八位AL。
汇编语言中分号不执行;
上机案例:
1)mov AX,1234H;等价于把1234H给AX
2)mov AH,12H;与下一条合并
mov AL, 34H;1和2等价
BX:基址寄存器(16位),可分为高八位BH和低八位BL。
CX:计数器,可分为高八位CH和低八位CL。
DX:数据寄存器,可分为高八位DH和低八位DL。
2* 指针及变址寄存器(16位)
SP:堆栈指针寄存器
BP:基址指针寄存器
SI:源变址寄存器
DI:目标变址寄存器
2. 4个段寄存器 (存储段地址)
1.CS:代码段寄存器(储存代码)
2.DS:数据段寄存器(数据存储区)
3.ES:附加段寄存器或特别段寄存器
4.SS:堆栈段寄存器
每个段区的大小允许根据实际需要来分配,而不一定要占有64KB的最大段空间。
实模式:存储器寻址空间 ≤ 1M
保护模式:存储器寻址空间 > 1M
缩写:
PA:物理地址
EA:有效地址
DS:段地址
BX:偏移地址
3. 2个控制寄存器
IP:指令指针寄存器,保存将要执行的下一条指令的偏移地址。
Flags:标志寄存器(保存运行结果的状态)贼重要!!!
标志寄存器(16位)
1.Flags有9个标志位,
其中6个状态标志位,
CF:进位/借位标志,表进位或借位,若存在进位或借位,CF=1,显示CY;CF=0 显示NC
PF:奇偶标志,运算结果的低八位有偶数个1,PF=1,显示PE;否则PF=0,显示PO
AF:辅助进位/借位,低4位向高4位有进位或借位,AF=1,显示AC;否则AF=0,显示NA
ZF:零标志,运算结果为0,ZF=1,显示ZR;否则ZF=0,显示NZ
SF:符号标志,运算结果为正,SF=0,显示PL;否则SF=1,显示NG
OF:溢出标志,运算结果溢出,OF=1,显示OV;否则OF=0,显示NV
3个控制标志位。
DF:方向标志,DF=0,增方向,显示UP;DF=1,减方向,显示DN
TF:陷阱标志,TF=1,每条指令执行完产生陷阱,TF=0,不产生陷阱
IF:中断标志,IF=1,中断允许,显示EI;IF=0,禁止终端,显示DI
例题:计算 9A3CH - 8A4BH = FF1
并指出6个状态标志位的值及debug的显示值
CF:0
PF:0
AF:0
ZF:0
SF:1
OF:0
debug显示:
:NC
:PO
:NA
:NZ
:PL
:NV
解:竖式计算中,C-B没有借位所以AF=0 ,显示NA
最高位向前没有借位,CF=0,显示NC
低八位中有奇数个1,PF=0,显示PO
运算结果不是0,ZF=0,显示NZ
运算结果为正,SF=1,显示PL
不溢出,所以OF=0,显示NV
上机实例:
课后老师还布置了一个作业:
1. 1234H+5678H =
2. 1234H-5678H =
解:
1.
代码验证:
2.
代码验证:
第9节课
寄存器每一位都是由触发器构成,触发器有三态,高电平低电平和高阻态。
寄存器和存储器的比较:
接口
1.接口:cpu外部设备的连接部件
2.接口分为芯片级和卡片级
每个接口包括一组寄存器:
数据寄存器:存放外设和主机间传送的数据
状态寄存器:保存外设或接口的状态信息
命令寄存器:保存CPU发给外设或接口的控制命令
了解一下:
8086cpu含40条引脚,16条引脚既能存地址也能存数据,后4根只能当地址线用。
第一个时钟周期得到的是地址编码,第二第三第四时钟周期得到的是数据编码。
保护模式:8086cpu管理的内存超过1MB
实模式:寻址空间≤1M
1.逻辑地址 段地址 :偏移地址
2.物理地址 段地址*10H+偏移地址
保护模式
1.逻辑地址 选择器 偏移地址(32位)寻址空间可到达4GB
2.物理地址 由选择器找到段地址再和偏移地址相加(选择器存放在段寄存器中,但寻找段地址通过描述符找到)
描述符用来描述段的大小、段在寄存器中的位置及其控制和状态信息,它由基地址、界限(段长度)、访问权(段的功能)、和附加字段(段的属性)四部分组成。
第10节课
一、汇编语言中指令的操作数
(1)立即数:以常数的形式出现在指令中
例: mov AL, 5 其中5为立即数
(2)寄存器操作数:以寄存器的名称出现在指令中
例:mov AX,BX 其中AX和BX为寄存器操作数
(3)存储器操作数:以带中括号的形式出现在指令中,操作数在内存单元中
例:mov AX,[0200H] 或 mov DX,[BX]
可放在中括号的寄存器:BX、BP、SI、PI
二、汇编指令格式
[标号:] 操作码 [操作数1] [操作数2] [;注释]
中括号代表可以缺省的指令
操作数1称为目标操作数,操作数2称为源操作数
例: AAZ: mov AX, 1234H;AX<-1234H
8086只有两个操作数
三、寻址方式
七种寻址方式:
1.立即寻址: 操作数是立即数(立即数不在内存中,在cpu中)
例:mov AL,5 源操作数为5,属于立即寻址
2.寄存器寻址:操作数以寄存器的名称出现在指令中
例:mov AL,5 目标操作数是AL,属于寄存器寻址
3.存储器寻址(5种):操作数在内存单元中即带中括号的操作数
(1)寄存器间接寻址:BX,BP,SI,DI带中括号。
例:mov [BX],25H,源操作数为25H,属于立即寻址;目标操作数为[BX],属于寄存器间接寻址
(2)直接寻址:
例:mov AX,[2000H] 将2001H的值给AH高八位,将2000H的值给AL低八位,所以AX为2A17H
(3)相对寻址:带了变量名就是相对寻址
变址:SI,DI
基址:BX,BP
例:mov AX, A[BX+SI]((4)相对基址变址寻址)
mov AX,A[BX][SI](两种写法)(只能基址和变址的搭配)
(5)基址变址寻址
例:MOV AX , [ BP ] [ DI ]
第11-12节课
有效地址在不同寻址方式中的定义:
立即寻址:立即寻址的有效地址为指令所在地址
寄存器寻址:寄存器寻址也是一种直接寻址
直接寻址:有效地址由指令直接给出
寄存器间接寻址:有效地址在基址寄存器(BX/BP)或变址寄存器(SI/DI)中
寄存器相对寻址:
基址变址寻址:
相对基址变址寻址:
段寄存器使用规定:
访问储存器的方式 | 默认的段寄存器 | 可跨越的段寄存器 | 偏移地址 |
---|---|---|---|
取指令 | CS | 无 | IP |
堆栈操作 | SS | 无 | SP |
一般数据访问 | DS | CE ES SS | 有效地址EA |
BP作为基址的寻址 | SS | CS DS ES | BP |
串操作的源操作数 | DS | CS ES SS | SI |
串操作的目的操作数 | ES | 无 | DI |
tips:
CS不能作目标操作数
目标操作数不能是立即数
串操作指令中目标段在ES中,源端在DS中
一条指令3个字节
段内直接传址:
转向的有效地址 = 当前(IP) + 位移量(8bit/16bit)
语法
JMP NEAR PTR NEXT 近转移 -32768 ~ +32767
JMP SHORT NEXT (short可省略) 短转移 -128 ~ +127
段内间接传址:
转向的有效地址是一个寄存器或存储单元的内容。
(可用除立即数以外的任何一种数据寻址方式得到)
例: TABLE = 20A2H (BX) = 1256H (SI) = 528EH
(DS) = 2000H (232F8H) = 3280H (264E4H) = 2450H
JMP BX ; (IP)=1256H
JMP TABLE[BX]
JMP WORD PTR TABLE[BX] ; (IP)=3280H
JMP [BX][SI]
JMP WORD PTR [BX][SI] ; (IP)=2450H
段间直接寻址:
用指令中提供的转向段地址和偏移地址取代CS 和 IP
段间间接寻址:
用存储器中的两个相继字的内容取代CS 和 IP
(存储单元的地址可用存储器寻址方式得到)
语法:
JMP DWORD PTR [INTERS+BX]
PA=(DS)×24 + (BX) + INTERS
(PA+1, PA)→IP
(PA+3, PA+2) →CS
第13-14节课
所有地址都是16位。
汇编语言的语句分三类:
1.指令语句:执行的语句
2.伪指令语句:不执行,提供给汇编程序汇编时使用
3.宏指令语句:由用户根据宏的定义格式,定义的指令执行的
数据传送指令
1.mov指令
格式: MOV DST, SRC ;DST<---SRC
功能:将源操作数SRC送给目标操作数DST
例:MOV AX,1234H;AX=1234H
注意:
DST、SRC不能同时为段寄存器如 MOV DS,ES
立即数不能直接送段寄存器 MOV DS, 2000H
目标操作数DST不能为CS和立即数
双操作数类型要一致(字节或字)
不影响标志位
2.堆栈指令
堆栈:内存空间的一部分,高地址向低地址延伸,具有后进先出或先进后出的特性。
‘先进后出’的存储区,段地址存放在SS中,SP在任何时候都指向栈顶,进出栈后自动修改SP。
1.入栈指令格式
push SRC;源操作数为子类型,只能为存储器操作数或寄存器操作数。
例:push BX
注意:
不能用立即寻址方式,例:PUSH 1234H
不影响标志位
DST不能是CS
必须以字为单位
思考题:已知AX=1234H,BX=5678H如何互换AX和BX的值,写出指令序列
方法一:
push AX
push BX
pop AX
pop BX
方法二:
mov CX,AX
mov AX,BX
mov BX, CX
方法三:
XCHG AX,BX;不允许使用段寄存器
;两个操作数不能同时是存储器操作数
例:xhcg[2000H],[3000H]
堆栈定义格式:
SABC segment stack
DW 100 dup(?);堆栈空间为100个字
SABC ends
;SABC为段名,stack表示定义堆栈,dup重复字句
上机实例:
说明:
8086cpu 端口地址有65536个,直接端口号:0-255 间接端口号:256-65535
3.输入/输出指令
输入输出端口地址不带中括号。
1.输入指令
格式:IN AL/AX,端口地址
功能:从指定端口地址输入1个字节或一个字到cpu中的AL或AX
(1)长格式:IN AL/AX,00-FFH
(2)短格式:mov DX,端口号
IN AL/AX,DX
2.输出指令
格式:OUT 端口号,AL/AX
功能:将cpu的一个字节或字 输出到指定的端口地址
(1)长格式:out 00-FFH,AL/AX(直接端口寻址)
(2)短格式:mov DX, 端口号(0-65535,前255个用长格式)
out DX,AL/AX
练习:分别用长格式和短格式的I/O指令,实现从28H端口处输入一个字,再输出到38H的端口处。
方法一:短格式
MOV DX,28H
IN AX,DX
mov DX,38H
OUT DX,AX
方法二:长格式
IN AX,28H
OUT 38H,AX
4.换码指令
格式:XLAT或XLAT OPR
功能:(AL)<--((BX)+(AL))
要求:先将换码表的首地址送BX,位移送AL再执行XLAT
例:MOV BX, OFFSET TABLE ; (BX)=0030H
MOV AL, 3
XLAT TABLE
指令执行后 (AL)=33H
5.地址传送指令
LEA REG(寄存器),<变量名>
功能:将<变量名>的偏移地址送寄存器REG
有效地址送寄存器指令: LEA REG, SRC
执行操作: (REG) <- SRC
指针送寄存器和DS指令: LDS REG, SRC
执行操作: (REG) <- (SRC)
(DS) <- (SRC+2)
相继二字 -> 寄存器、DS
指针送寄存器和ES指令: LES REG, SRC
执行操作: (REG) <- (SRC)
(ES) <- (SRC+2)
相继二字 -> 寄存器、ES
该命令不影响标志位
REG不能是段寄存器
SRC必须是存储器操作数
例子:
图片有些不清楚,但应该能看见,存在这样一段数据。
例子:
LEA DX,B+2; DX=0005
将变量B+2的偏移地址送DX
LEA DX, B+5; DX=0008
LEA DX, A+7;DX=0007
LDS REG,SRC
功能:地址指针传送指令,SRC为双字操作数,低字送REG,高字送DS
例:
LDS BX,C
DS = 5678H
BX = 1238H
LDS BX, DWORD PTR B+1;DWORD PTR表示按双字访问
BX = 7212H
DS=3807H
访问方式
byte PTR 变量 强制按字节访问
word PTR 变量 强制按字访问
Dword PTR 变量 强制按双字访问