NJUPT【 汇编语言 】
一.数制
真值数和补码数之间的转换方法 : [[X]补]补 = X
设设机器数字长n, 则n位补码数,
**有符号数真值范围为 -2^n-1^ ~ +2^n-1^-1**
**无符号数其数值范围为** 0~2^n^-1
<center>常用ASCII码</center>
原数字 | ASCII(D) | ASCII(H) |
---|---|---|
0 | 48 | 30H |
A | 65 | 41H |
a | 97 | 61H |
CR(回车) | 13 | 0DH |
换行 | 10 | 0AH |
二.基本结构
字长:字长是微处理器一次可以直接处理的二进制数码的位数
实模式特点
- 加电复位之后,486自动工作在实模式,系统在DOS管理下
- 实模式下,486只能访问第一个1M(==220==)内存(00000H - FFFFFH)
- 存储管理部件对存储器只进行分段管理,没有分页功能,一个逻辑段最大容量为==64K==
- 实模式下,段寄存器中存放段基址
保护模式特点:
- 支持多任务操作系统
- 保护模式下,可以访问4G(232)物理存储空间
- 采用分段和分页功能
三个存储地址空间:
- 逻辑空间 可以达到246=64T
- 线性空间
- 物理空间
冯诺以曼体系
CPU: 运算器和控制器
主要包括以下几个部分:存储器、运算器、控制器、输入设备、输出设备
486内部结构
<center>常用通用寄存器</center>
通用寄存器
指令 = 操作码 + 操作数
32位微处理器地址空间
- 物理空间:程序的运行空间,即主存空间,在486中,共32条地址线,内存最大容量为4G
- 虚拟空间: 编程空间,虚拟存储器是一项硬件和软件相结合的技术。
状态标志寄存器
8086标志寄存器共有15个标志位置,分为两类 状态标志 和 控制标志
1.条件(状态)标志
进位标志: A标:低半字节位是否出现借位或者是进位,有为1,无为0
辅助进位: C标:最高为值是否出现借位或者是进位,是为1,无为0
O标:是否溢出,是则1,无则0,如果最高位不同,一定不会溢出。
Z标:结果是否为0,是则1,无则0
P标:运算结果低8位中1结果的1的次数是否为偶数,是则1,否则0
S标:最高位是否为1,是则1,否则0
2.控制标志
TF标:设置为1时,CPU进入单步模式,所谓单步模式就是CPU在每执行一步指令后都产生一个单步中断
IF标志:IF为1时,CPU允许响应外部的可屏蔽中断请求。I=0的时候屏蔽
DF标:。使用CLD指令清0, DF为1时,串操作指令按递减方式改变有关[存储器](https://baike.baidu.com/item/存储器)指针值,每次操作后使SI、DI递减。
实模式下物理地址的形成
- 逻辑地址是程序员赋予的,是不唯一的
- 物理地址是唯一的,不同的逻辑地址可以表示一个物理地址
逻辑段 | 段基址存放在 | 偏移地址存放在 |
---|---|---|
代码段 | CS | IP |
堆栈段 | SS | SP |
数据段 | DS | 根据不同的寻址方式BX、BP、SI、DI |
附加段 | ES/FS/GS | 根据不同的寻址方式BX、BP、SI、DI |
CS、IP的初值: 由操作系统赋值
SS、SP的初值:
- 程序员赋值
- 操作系统赋值
DS/ES/FS/GS的初始值:由程序员赋值
BX/SI/DI/BP的初始值:由程序员赋值
三.汇编基本知识
a. 操作数寻址方式:star::star::star::star::star:
指令当中的操作数 : 立即数、 寄存器数、内存操作数、I\O端口操作数
那么各个数有各个访问操作数的方式:
- 访问立即数
- 立即寻址:heavy_check_mark:
- 访问寄存器数
- 寄存器寻址:heavy_check_mark:
- 访问内存操作数:
- 直接寻址:heavy_check_mark:
- 间接寻址:heavy_check_mark:
- 基址寻址:heavy_check_mark:
- 变址寻址:heavy_check_mark:
- 基址加变址寻址:heavy_check_mark:
1.立即数寻址
直接用立即数进行赋值
mov ax, 1000H 将1000H赋值给ax
2.寄存器寻址
直接把一个寄存器的值送给另一个寄存器
mov ax,bx ;将bx寄存器的值赋值到ax中
3.直接寻址
-
段寄存器:[偏移地址]
偏移地址用立即数来表示的为直接寻址
mov al, es:[2CH] 从ES段偏移地址位2CH的单元取数 -> al mov ax, ds:[2000H] 从数据段偏移地址为2000H的单元取一字, ->ax
-
段寄存器:变量名
mov ax, es:[YY] YY里面的内容作为偏移地址
4.间接寻址
又称间接寻址,间址。操作数在内存单元中,段基址放在段寄存器中,偏移地址在==间址寄存器==当中。
地址表示:段寄存器:[间址寄存器]
物理地址 = 段寄存器 * 16 + 间址寄存器
<center><i>表1.间址寄存器和约定访问逻辑段
间址寄存器 | 约定访问的逻辑段 | |
---|---|---|
BP | 堆栈段 SS | 16位寻址方式 |
BX, SI, DI | 数据段 DS | 16位寻址方式 |
EBP, ESP | 堆栈段 SS | 32位寻址方式 |
EAX~EDX, ESI, EDI | 数据段 DS | 32位寻址方式 |
mov ax, [bx] //约定的默认段寄存器为DS, 所以会访问 DS:[BX]
5.基址寻址
基址寻址的地址表达式:段寄存器:[基址寄存器+位移量]
物理地址: 段寄存器 * 16 + 基址寄存器 + 位移量
<center><i>表2.基址寄存器和约定访问逻辑段
变址寄存器 | 约定访问的逻辑段 | 适用于 |
---|---|---|
BP | 堆栈段 | 16位 |
BX | 数据段 | 16位 |
EBP, ESP | 堆栈段 | 32位 |
EAX~EDX, ESI ,EDI | 数据段 | 32位 |
mov al, [bx + 2] 物理地址:DS * 16 + bx + 2
6.变址寻址
基址寻址的地址表达式:段寄存器:[比例因子变址寄存器+位移量]*
物理地址 :段寄存器 * 16 + 比例因子 * 变址寄存器 + 位移量
<center><i>表3.变址寄存器和约定访问逻辑段
变址寄存器 | 约定访问的逻辑段 | 适用于 |
---|---|---|
SI, DI | 数据段 | 无比例因子,16位寻址 |
EBP | 堆栈段 | 有比例因子, 32位寻址 |
EAX~EDX, ESI ,EDI | 数据段 | 有比例因子,32位寻址 |
==如何区别变址和基址寻址?==
我们通过表1和表2可以知道,在基址寻址过程中,我们使用的基址寄存器为BP、BX,而变址寄存器中使用的位SI、DI。所以我们可以作出区分。
7. 基址+变址寻址
基址寻址的地址表达式:段寄存器:[基址寄存器 + 比例因子变址寄存器+位移量]*
mov al, [BX + SI + 0250H] 物理地址= DS * 16 + BX + SI + 0250H
末.总结
mov al, 0120H 立即寻址
mov al, Bl 寄存器寻址
mov AL,DS:[1000H] 直接寻址
mov AL,BUF 直接寻址
mov AL,[BX] 间址寻址
mov AL,[BX+1] 基址寻址
mov AL,[SI+1] 变址寻址
mov AL,[BX+SI] 基址加变址寻址
b. 汇编语言指令
语句是汇编语言汇编和执行的单位,汇编语言源程序包括的语句类型位:指令性语句和指示性语句。
标号代表该条指令的符号地址。
- 指令性语句(符号指令) :经过汇编之后,通知CPU进行什么操作。
- 指示性指令
- 伪指令:非机器指令,是在汇编链接期间进行操作的
- 宏指令
符号指令和机器指令是一一对应的关系。
1.常用伪指令语句
-
数据定义伪指令
-
字节定义伪指令 : DB(Define Byte的缩写) 长度为8位 单字节数
N1: DB 12H,64,-1,3*3 DB 'A','B' N2: DB ?,?,? 或者是 DB
-
字定义伪指令:DW(Define Word的缩写) 长度位16位 双字节数
WNUM: DW 1234H, 56, 'AB', 'C' DW ?,? 汇编后: 34H, 12H, 38H, 00H, 42H( ASCII B), 42H( A's ASCII) , 43H, 00H
-
-
符号定义指令
-
等值伪指令 : EQU
NUM EQU 33 类似于C语言中的define语句
-
等号伪指令 : =
NUM = 33
EQU和=的区别,EQU定义的NUM在后继语句当中不能被重新定义,而后者可以被重新定义。
-
2.常用运算符
-
$运算符
作用:代表所在位置的地址
BUF DB ‘assembly is ok’ ;字符串长度位14 LLL EQU $-BUF ;返回从BUF运算符到当前位置的长度,也就是一共分配了多少单元
-
SEG 运算符
作用:计算某一段逻辑段的段基址
mov ax, SEG DATA mov ds ,ax
-
OFFSET 运算符
作用:计算某个变量名和标号名所在单元的偏移量
BUF DB 12H, 34H, 56H MOV BX OFFSET BUF MOV AL, [BX] ;AL = 12H
-
PTR 运算符
作用:临时修改某一单元内存的属性
类型属性确定的操作数
- 寄存器操作数
- 用变量名直接寻址的内存操作数
类型属性不确定的操作数
- 立即数
- 非变量名定义的内存操作数(带括号)
BUF DB 11H,22H,33H,44H EXAMPLE_1: MOV AX, BUF ;不正确,前后位数不一样 MOV AX , WORD PTR BUF ;AH = 22H, AL = 11H EXAMPLE_2: MOV BUF, 1234H ;错误 MOV WORD PTR BUF, 1234H ;正确,BUF单元变为34H, BUF+1单元变为12H EXAMPLE_3: MOV BX, OFFSET XX MOV [BX], 12H MOV BYTE PTR [BX], 12H ;将BX单元的内容变为12H MOV WORD PTR [BX], 12H ;将BX单元的内容变为12H,将BX+1单元的的内容变为00H
3.汇编基本指令集
1.通用传送类指令
-
数据传送指令
mov des , source WARNING: MOV DS, 1000H ;不合法,立即数不能直接赋值给段寄存器 MOC CS, 1000H ;不合法,不嫩修改CS的值
-
符号扩展指令
MOVSX: 符号位向高位扩展,再送给目标操作数
MOVZX:符号位高位补0, 再送给目标操作数
movsx DL, -16 ;DL = F0H movsx bx, dl ;bx = FFF0H 符号位为1,扩1 movzx bx, dl ;bx = 00F0H 括0
-
有效地址传送指令
LEA运算符等效于OFFSET运算符
lea bx, buf == mov bx, offset buf
-
交换指令
XCHG:两个操作数互换;
说明: 段寄存器、 立即数不能参加互换
2个内存操作数不能参与互换,前后属性要一致。
2.堆栈操作类指令
堆栈栈顶在栈区的低地址,栈底在栈区的高地址。
堆栈段寄存器 SS;
堆栈指针ESP和 SP;
-
进栈指令
PUSH 源操作数
SP = SP - 2 高8位 --> SS:[SP+1] 高字节 低8位 --> SS:[SP] PUSH WORD PTR [BX] ;将DS:[BX]的内容压栈
-
出栈
SP = SP + 2 SS:[SP] -- > 低8位 SS:[SP+1] --> 高8位
3.运算类指令
二进制加法:
-
加减运算法指令 当操作数为内存数的时候必须使用PTR运算符
- INC 目标操作数 :加1指令 必须
- DEC 目标操作数 :减1指令
-
乘除运算类指令
<center><i>表4.乘法功能
MUL/IMUL 被乘数默认在 乘数为 高位积在 低位积在 字节相乘 AL R8/M8 AH AL 字相乘 AX R16/M16 DX AX 双字相乘 EAX R32/M32 EDX EAX <center><i>表5.除除法功能
DIV / IDIV 被除数默认在 除数为 商值在 余数在 字节除法 AX R8/M8 AL AH 字除法 DX=高16位 , AX=低16位 R16/M16 AX DX 双字除法 EDX=高32位 , EAX=低32位 R32/M32 EAX EDX -
无符号数乘法:
MUL 乘数
- 格式一
MUL 目
功能:被乘数默认在EAX中 - 格式二
MUL 目 源
- 格式三:
IMUL 目,源, 立即数
源*立即数 = 目标操作数
MOV EAX, 15000 MOV EBX, 12 MUL EBX ;15000*12 --> EAX
- 格式一
-
有符号乘法:
IMUL 乘数
-
无符号除法 DIV
-
有符号除法 IDIV
-
-
NEG指令 : 求补运算 可以表达成 取反后 +1, 可以用来求一个数的相反数
MOV AL, 77 NEG AL ;result : AL=-77
-
SBB指令 :除完成SUB减法运算外,还要减去借位CF,结果送到目的操作数,按照定义影响6个状态标志位。也就是
SBB dest,src ; 带借位减法:dest=dest-src-CF
-
ADC指令:带进位加法指令 ADC(Addition Carry)
ADC OPRD1,OPRD2 ;OPRD1 = OPED1 + OPRD2 + 1
4.BCD码调整指令
-
DAA指令默认的操作对象是AL寄存器,将AL寄存器里面的值变为BCD码
;计算1234+5678=? 结果用BCD码表示 ;数据段 N1 DW 1234H N2 DW 5678H SUM DW ? ;代码段 MOV AL, BYTE PTR N1 ADD AL, BYTE PTR N2 DAA MOV BYTE PTR SUM, AL MOV AL, BYTE PTR N1+1 ADD AL, BYTE PTR N2+1 DAA MOV BYTE PTR SUM+1, AL
-
DAS
默认操作对象是AL,对AL中的组合BCD差值进行修正。
- 若被减数>减数,调整后,C标=0,AL=组合BCD码差值;
- 若被减数<减数,调整后,C标=1,AL=差值相对于模100的补数。
;计算56-78 = ? ;数据段 MOV AL, 56H SUB AL, 78H DAS ;结果:C=1,AL=78H
5.转移指令
-
无条件转移
jmp xyz ;无符号跳转到xyz
-
有条件转移
-
无符号条件转移
CMP N1,N2 ;N1,N2都为无符号数 JA XYZ ;N1 > N2转移 JNA XYZ ;N1 <= N2转移 JC XYZ ;N1 < N2转移 JNC XYZ ;N1 >= N2转移 JZ XYZ ;为零跳转
-
有符号数条件转移
CMP N1,N2 ;N1,N2都为有 符号数 JG XYZ ;N1 > N2转移 JGE XYZ ;N1 <= N2转移 JL XYZ ;N1 < N2转移 JLE XYZ ;N1 >= N2转移
-
-
循环控制转移 LOOP
;TEST:某班级40人,某课程成绩存放在SCORE开始的内存单元,统计合格人数 ;数据段 SCORE DB XX,XX,XX; OK DB ? ;代码段 MOV AX, SEG SCORE MOV DS, AX MOV BX, OFFSET SCORE MOV CX, 40 MOV DL, 0 LAST: CMP BYTE PTR [BX], 60 JC NO;如果成绩小于60 INC DL;及格人数加1 NO: INC BX;偏移地址+1,判断下一个人数 LOOP LAST;如果CX=0的时候,跳转到LAST MOV OK,DL
6.子程序调用与返回类指令
7.串传送指令
说明:
- 源串和目标串的存储及寻址方式都有隐含规定,源串要放在数据段,目标串要放在ES附加段
- CPU自动用SI间址访问数据段,用DI间址访问ES附加段、用CX做为串计数器。
格式:
- 字节串传送: MOVSB
- 字串传送: MOVSW
- 双字串传送:MOVSD
功能:把DS:[SI]传送到ES:[DI]
8.逻辑运算指令
名称 | 格式 | 功能 | 影响的标志位 |
---|---|---|---|
逻辑与操作 | AND | 与 | S Z P |
逻辑或指令 | OR | 或 | S Z P |
逻辑非指令 | NOT | 非 | 不影响 |
异或指令 | XOR | 异或 | S Z P |
测试指令 | TEST | 测试 | S Z P |
Test指令:Test对两个参数(目标,源)执行AND逻辑操作,并根据结果设置标志寄存器,结果本身不会保存。
如果结果为0,那么ZF标志位为1 使用JZ跳转
9.移位指令
操作数智能为cl寄存器或者是立即数
- 逻辑左移位 : SAL 或 SHL ,低位补0, 进位到CF中
- 逻辑右移位: SHR, 高位补0 无符号数
- 算术右移位: SAR ,高位补原来的最高位 符号位保持不变
-
循环右边移位:
image
10.处理机控制类指令
CLC ;复位进位标志:CF←0
STC ;置位进位标志:CF←1
CLD ;复位方向标志:DF←0
STD ;置位方向标志:DF←1
CLI ;复位中断标志:DF←0
STI ;置位中断标志:DF←1
四.汇编语言程序设计
1.完整的源程序结构
- 用方式选择伪指令来说明该程序的微处理器类型
- 用段定义语句定义每一个逻辑段
- 用ASSUME语句说明段约定
- 用汇编结束语句说明源程序到此结束
.586 ;方式定义 表示整个源程序经过汇编链接之后生成哪种CPU类型的机器指令 向下兼容 如果缺省直接8086
DATA SEGMENT USE16 ;段定义语句,USE16定义,有效对有效地址为16位,逻辑段长度最大运行为64K 缺省的是USE32 所以在实模式下不能忘记\
...
DATA ENDS ;段结束
CODE SEGMENT USE16 ;定义代码段
ASSUME CS:CODE, DS:DATA ;段约定,用来表示CODE段和CS寄存器进行绑定,DATA段和DS寄存器进行绑定。
BEG:
MOV AX, DATA
MOV DS, AX
...
MOV AH,4Ch
INT 21H ;程序结束到此结束,把操作权给汇编程序
CODE ENDS
END BEG ;通知汇编程序,源程序到此结束法,用BEGIN
2. 开发过程
编辑程序 –> .ASM文件 –> 汇编程序 –> .OBJ文件 –> 链接程序 –> .EXE文件
a.asm --> ml /c a.asm --> link a.obj --> a.exe
3.开发格式
- .exe
- .com 优先级比exe高
异同点
EXE文件:允许源程序使用多个逻辑段
实模式下,每个逻辑段不超过64K
COM文件:源程序只允许一个逻辑段 就是代码段
需要使用定位ORG指令将程序的启动指令放在 代码段偏移地址为100H的单元地址
程序使用的数据可以集中在代码段的开始或者末尾
4.DOS功能调用
BIOS/DOS调用模式
MOV AH, 功能号
设置入口参数
INT 21H
分析出口参数
功能号:
- 01H 等待键入一个字符,有回显,相映Ctrl_C
- 02H 显示一个字符 从DL读入 但是会破坏AL寄存器的内容
- 07H 等待键入一个字符,无回显
- 出口参数 : AL=按键的ASCII码
- 08H 等待键入一个字符
- 09H 显示一个字符串
- 入口参数: DS:DX = 字符串首地址,字符串必须以 ‘&’(ASCII码为24H)为结束符号
- 0AH 等待键入一串字符串送入数据缓冲区
- 入口参数: DS:DX 指向放入的字符的缓冲区
- 出口参数: 存放于缓冲区的字符串,以回车键结尾
5.BIOS功能调用
-
01H 查询键盘缓冲区
- 出口参数: Z标志 = 0 , 有键入,键代码仍保留在键盘缓冲区中,此时AL= 键入字符的ASCII码,AH=键入字符的扩展码 Z标志=1,表示无键入
-
0EH 显示一个字符
- 入口参数 从AL读入
-
13H 显示一个字符串
- 入口参数 属性字节BL ,
5.程序设计格式
- 分支程序设计
- 循环程序设计
6.子程序设计
主
7.宏指令程序设计
宏体被COPY一份插入在位置上。是由汇编程序执行的。所以不会减少体积。
宏程序和子程序的异同点:
相同点:宏指令与子程序都可以简化程序设计,增强程序的可读性
不同点:
- 子程序调用的是由CPU完成的,宏指令的调用是在汇编程序中完成的
- 子程序的调用可以减小目标程序的体积,但是宏指令不可以
8.代码转换
- 十六进制转为二进制输出
.586
DATA SEGMENT USE16
MESG DB 'Please Enter!',0DH,0AH,'$'
DATA ENDS
CODE SEGMENT USE16
ASSUME CS:CODE,DS:DATA
BEG:
MOV BX, DATA
MOV DS, BX
;显示一行字符串
MOV AH , 9
MOV DX, OFFSET MESG
INT 21H
;输入一个字符
MOV AH, 1
INT 21H
;比较字符串
CMP AL, 39H
JNA NEXT1
SUB AL, 7H
NEXT1:
SUB AL,30H
;27行的2号功能会破坏AL的值,所以不能使用AL的值
MOV BL, AL
;输出 = 符号
MOV AH,2
MOV DL, '='
INT 21H
;输出二进制
CALL DISP
;输出B
MOV AH,2
MOV DL, 'B'
INT 21H
EXIT:
MOV AH, 4CH
INT 21H
;显示函数
DISP PROC
MOV CX,8
LAST:
MOV DL, '0'
RCL BL,1
JNC NEXT
MOV DL, '1'
NEXT:
MOV AH,2
INT 21H
LOOP LAST
RET
DISP ENDP
CODE ENDS
END BEG
-
十六进制输出
.586 ;将BUF单元中的数字转为16进制 DATA SEGMENT USE16 BUF DW 987AH DATA ENDS CODE SEGMENT USE16 ASSUME CS:CODE, DS:DATA BEG: MOV AX, DATA MOV DS, AX MOV DX, BUF MOV CX, 4 ;算术左移,低位补0 SAL EDX, 16 AGA: ROL EDX, 4 AND DL, 0FH CMP DL ,10 JC NEXT ADD DL, 7 NEXT: ADD DL, 30H MOV AH, 2 INT 21H LOOP AGA MOV AH, 4CH INT 21H CODE ENDS END BEG
-
16进 制转为 十进制显示程序
.586 CMPDISP MACRO NN ;设置一个宏 LOCAL LAST,NEXT MOV DL,0 LAST: CMP BEN,NN JC NEXT INC DL SUB BEN, NN JMP LAST NEXT: ADD DL,30H ;ASCII ENDM DATA SEGMENT USE16 BEN DW 1287H ;4743 TAB DW 10000,1000,100,10,1 COUNT EQU ($-TAB)/2 ;查看TAB分配了多少单元格 BUF DB COUNT DUP(?),'$';输出缓冲区 DATA ENDS CODE SEGMENT USE16 ASSUME CS:CODE, DS:DATA BEG: MOV AX, DATA MOV DS, AX MOV CX, COUNT MOV BX, OFFSET TAB MOV SI, OFFSET BUF AGA: MOV AX, [BX] CMPDISP AX MOV [SI], DL ADD BX, 2 INC SI LOOP AGA MOV SI, OFFSET BUF NOSP: CMP BYTE PTR[SI], 30H JNZ DISP INC SI JMP NOSP DISP: MOV AH, 9 MOV DX, SI INT 21H MOV AH, 4CH INT 21H CODE ENDS END BEG
五.MOOC题目
第一章
image第二章
image第四章
image第五章
image第六章
image第七章
imageimage