汇编语言
地址总线
计算机组成:
cpu
数据总线
内存
控制总线.
指令和数据在存储器(内存)中存放
数据和指令都是二进制信息
1000100111011000可以是数据可以是指令
89D8H(数据) MoV Ax, Bx(指令)
数据的表示:
几乎不用
1000100111011000B(工进制)89D8H(十六进制) 1047300(八进制)35288D(十进制)
数据量:B,KB,XAB,GB、TB 1KB=1024B
存储单 元 0127 1个FFFFH)内存地址空间为IMB
存储器被划分为若干个存储单元.每个存储单元从0开始顺序编号(共128个)
8086共有20条数据线,寻址空间:2²⁰,为IMB (0
总线:连接CPU和其他芯片的导线
CPU通过地址总线指定存储单元.地址总线宽度决定了可寻址的存储单元大小,N根总线(宽度为N)对应寻址空间为2^{N}
CPU通过数据总线进行传输,宽度决定传送速度
CPU通过控制总线对外部器件进行控制,宽度决定控制能力
x86 CPU性能一览 516TU学
CPU 地址总线宽度 寻址能力 数据总线宽度 一次传送数据 读取1KB数据要读_次
8080 16 640KB 8 1B 1024
8088 20 1MB 8 1B 1024
8086 20 1MB 16 2B 512
80286 24 16MB 16 2B 512
80386 32 4GB 32 4B 256
NOTE
Created by Notein
CPU对存储器的读写
存储单元的地址
三类信息的交互
器件选择和读写命令
读写的数据
RAM:随机存储器,能读写,存动态的 主板上的RAM,例显卡.扩展槽
ROM:只读存储器,启动要用的信息系统BIOS,接口卡上的BIOS
RAM(主存储器)
ROM(装有系统BIOS)
RAM(主存储器)
内存条
扩展插槽
显卡
RAM(显存)
ROM(装有显卡BIOS)
扩展插槽
网卡
ROM(装有网卡BIOS)
扩展插槽
将各类存储器看作一个逻辑存储器.统一编址
(将所有的物理存储器被看作一个由若干存储单元组成的逻辑存储器)
每个物理存储器占有一个地址段,即一段地址空间
RAM(主存储器)
主存储器
ROM(装有系统BIOS)
NOTE
CPU
地址空间
Created by Notein
RAM(主存储器)
内存条
扩展插槽
显存
显卡
地址空间
RAM(显存)
ROM(装有显卡BIOS)
显卡BIOS ROM
地址空间
网卡BIOS ROM
扩展插槽
地址空间
网卡
ROM(装有网卡BIOS)
系统BIOS ROM
地址空间
扩展插槽
8086PC机分配
00000
主存储地址
空间64ok
RAM
9FTF
A0000 显存128K
BFFFF RAM
C0000 ROM 256KB
FFFFF
访问寄存器和内存
8086CPU有14个寄存器: 都是16位.
通用寄存器: AX、BX、CX、DX 可以存放2字节
变址寄存器 : SI、DI
指针寄存器 : SP、BP
指令指针寄存器: IP
段寄存器: CS、SS、DS、ES →不能直接赋值
标志寄存器 : PSW
以AX为例.可以存储16位数据.
最大值2¹⁶-1,FFFFH
NOTE
Created by Notein
高8 低8
8位兼容:通用寄存器分为两个独立的8位寄存器使用(Ax→AH和AL)
“字”的存储
8086的字长为16bit,一个字为16bit
mov和 add指令
汇编指令 控制CPU完成的操作 用高级语言的语法描述
mov ax,18 将18送入AX AX = 18
mov ah,78 将78送入AH1 →Ax高8位 AH = 78
add ax,8 将寄存器AX中的数值加上8 AX = AX + 8
mov ax, bx 将寄存器BX中的数据送入寄存器AX AX = BX
add ax, bx 将AX,BX 中的内容相加, 结果存在AX中 AX = AX + BX
汇编指令不区分大小写,只有数字是10进制
程序段中的指令 指令执行后AX中的数据 指令执行后BX中的数据
mov ax, 4E20H 4E20H 0
add ax, 1406H 6226H O
mov bx, 2000H 6226H 2000H
。 add ax, bx 8226H 2000H
mov bx, ax 8226H 8226H
add ax, bx O44CH(溢出) 8226H
程序段中的指令 指令执行后AX中的数据 指令执行后BX中的数据
mov ax, 001AH 001AH 0000H
mov bx, 0026H 001AH 0026H
add al, bl 0040H 0626H
add ah, bl 2640H 0026H
add bh, al 2640H 4026H
mov ah,0 0040H 40261-1
add al, 85H 00C51-1 4026H
Created by No
add al, 93H 0058H 4026H NOTE
85+93=158“溢出
物理地址
所有内存单元构成一个一维的线性空间
每一个单元在这个空间都有一个唯一地址,称为物理地址
8086给出物理地址的方法;
用两个16位地址(段地址,偏移地址)合成一个20位的物理地址物理地址=段地址×16+偏移地址
左移4位
例 偏: 段:\frac {1230}{1230}123C8物理地址的段地址和偏移地址不唯一
物:
内存分段表示法
段地址 内存并没有分段,段的划分来自CPU
一般取起始地址前16位(4位)为段地址
一定是16的倍数,偏移地址为16位,最长为64K,变化范围0~FFFFH表示方法 数据存在 2000:1F60单元中.
数据存在内存2000H段中1F60H单元中
段地址很重要,CPU用专门的寄存器存放段地址
4个段寄存器
CS-代码段 DS-数据段
SS一栈段 ES-附加段
NOTE
Created by Notein
Debug
debug ——启动 debug
r–查看寄存器的内容
r寄存器名——改变指定寄存器的内容
d-列出预设地址内存处的128个字节的内容
d段地址:偏移地址一列出指定地址内容
d段地址:偏移地址结尾偏移地址一列出指定范围内容
e段地址:偏移地址 数据1 数
据2……——将内容写入指定
地址
e段地址:偏移地址
逐个询问式修改
空格——接受,继续
回车——结束 debug里面数字默认为16进
u地址——查看代码 制.不用写H
a地址——写入汇编指令
t——执行 cs: ip的指令
q——退出 debug
NOTE
Created by Notein
CS, IP与代码段
CS:代码段寄存器 段:偏
IP:指令指针寄存器
CS:IP—CPU将内存中CS:IP指向的内容当作指令执行
工作过程:
(1)从CS:IP指向内存单元读取指令,指令进入指令缓冲器.
(2)IP=IP+所读指令的长度
(3)执行指令,转到步骤(1)重复.
imp指令
改变CS,IP的内容,转移流程,来控制CPU要执行的目标指令r命令可以改变寄存器的值, rcs, rip(调试手段并非程序方式) mov CS,2000H X禁止
IP只能CPU自己通过运行程序代码来更改
同时修改CS,IP的内容;jmP_段地址:偏移地址
仅修改IP的内容 jmp 某一合法寄存器, jump ax(类似于 ax移到IP内)
内存中字的存储
16位=一个字(看机器是多少位的)
Ax
例moV a X 4E20H 4E存在高8位,20存在低8位
4EH 20H
如 2000OD中,4E20H存放在0.1两个单元,那E在1,20在0
AH
AL
0 20H / 4EH 4E20H 先读高地址2 12H
3 00H
NOTE
Created by Notein
只要连续即可
字单元:由两个地址连续的内存单元组成,存放一个字型数据
例 0地址单元中存放的字节型数据是20H,
2
12H
3
00H
0地址单元中存放的字型数据是4E20H,
4
DS和数据段
用DS存放数据段的段地址,单元地址由 address指出
指令形式 例示
mov寄存器 , 数据 mov ax,8
mov寄存器, 寄存器 mov ax, bx
mov寄存器 , 内存单元 mov ax, [0]
mov内存单元 , 寄存器 mov[0], ax
mov段寄存器 , 寄存器 mov ds, ax
add指令形式 例示
add寄存器 , 数据 add ax,8
add寄存器 , 寄存器 add ax, bx
add寄存器, 内存单元 add ax,[0]
add内存单元, 寄存器 add [0], ax
sub指令形式 例示
sub寄存器 , 数据 sub ax,8
sub寄存器 , 寄存器 sub ax, bx
sub寄存器 , 内存单元 sub ax, [0]
sub 内存单元, 寄存器 sub [0], ax
减法 sub
NOTE
Created by Notein
栈及栈操作
栈:只能在一端进行插入或删除操作,后进后出
PUSH(入栈),POP出栈
push ax:将 ax中的数据送入栈中.
pop ax:从栈顶取出数据送入 ax(以字为单位对栈操作)
栈寄存器SS,存放栈顶的段地址
栈顶指针寄存器SP — 存放栈顶的偏移地址
SP会减小入栈
例:交换 ax和 bx的值.
mov ax,1000H , mov ax,oolAH, push ax, pop ax
mov ss, ax : mo v bx,oolBH, push bx, pop bx
()
1
mov sp,0010H 1
Ax Bx S s S P Ax Bx Ss SP SP Ax Bx SP1000H 1000H 0010 00lAH 00lBH 1000H0010 000C 001BH 00AH 0010
push ax :(1)SP=SP-2(2)将 ax中的内容送入SS: sp指向的内存单元处, ss: sp此时指向新栈顶
pop ax: (1)将SS: sp指向的内存单元处的数据送入 ax(2)SP₂SP+2,作为新栈顶
cpu不保证对栈的操作不会越界
栈段的最大容量是64KB
NOTE
Created by Notein
段的总结:
物理地址:段地址×16+偏移地址
数据段在 ds,
代码段在CS,偏移在IP 三个段地址可以是一样的栈段在SS.偏移在SP
汇编语言源程序
伪指令:没有对应的机器码,不由CPV执行,由编译器来执行指令
assume cs: codesg
codes g segment
丷
mov ax 4cooh} 程序结束后将CPU的控制权
int 21h 1 交还给使它得以运行的程序(常为DOS系统)
Codes g ends
end
程序中的三种伪指令
段定义:
一个程序由多个段组成,用来存放代码,数据,或作为栈空间至少要有一个段用来存放代码
段名 segment 一一段的开始
段名 ends–段的结束
Created by Notein
end:
汇编程序的结束标记,若不加 end,则编译器在编译程序时.无法知道程序在何处结束
assume(假设)
假设某一段寄存器和程序中定义的段相关联.例 assume CS: codesg、指CS寄存器与 codesg关联
;注释
由源程序到程序运行
源文件. asm 编译,目标文件. obj连接可执行文件. exe
LST:中间结果. CRF:中间结果
masm运行方法:
DosBox→mount Cd:\masm→文件位置
→masm 文件名. asm (DoSBox编译,产生. obj)
连接: link 文件名(产生. exe)
执行 exe;直接输入文件名 ( debug 文件名. exe)
运行和跟踪
P命令类的T命令.但遇到子程序.中断艾,直接执行.然后显示结果G命令,从指定地址处开始运行程序,直到遇到断点,或者程序正常结束
NOTE
Created by Notein
[]和( )
[]–(汇编语言语法规定)表示一个内存单元
( )一一表示一个内存单元或寄存器中的内容,是一种书面的描述方法,(ax)=00∣0H即表示 ax中内容为0010H
①只能用寄存器及物理地址
例 mov ax.[2]的功能(ax)=(1ds)⁺16+2)
add ax,2(ax)=(ax)+2
push ax(1SS)^{ \times }16+(SP))=(ax)
符号 idata表示常量 1,2,3,…
inc bx 表示bx=bx+1(不理解就画寄
存器)
loop指令
实现循环(计数型循环)
loop 标号
例
assume cs: code
code segment
mov ax, 2 本代码共循环11次
mov (x,1)
s : add ax, ax 执行后: cx存放循环次数
loop s
(CX)=(CX)-1;
判断.(x≠0,继续执行s,
Cx=0,向下执行
NOTE 结果: 12,类似 do… while Created by Notein
在汇编源程序中,数据不能以字母开头.若数据为++ff.则写作Offff,在前面加若是只取字节的值,可以先将数据取出,再根据需要,将高位置0即可.
例子:计算ffff:0006字节单元中的数乘以3.结果存储在 dx中:
asscume cs: code
code acgment
mov ax, offfh
mov ds, ax mov al,[ bx]→段地址为 ds, mov bx, b偏移地址为 bx内 mov ah, 0
mov dx,0 存储的数据
mov cx,3
S: add dx, ax
loop s
mov ax,4cooh
int 21h
code ends
end
段前缀
在[idata]前显式地写上段寄存器
mov ax, zoooh
mov ds, ax 段前辍
mov bx,0
mov ax, ds:[ bx]
访问连续的内存单元
做法:取出8位数据,加到16位的寄存器
寄存器可以类比变量
mov bx,o add dx, ax
assume cs: code mov dx,0 inc bx code ends
code segment mov cx,12 100P S end
mov ax, offth S: mov al,[ bx] mov ax,4cooh mov ah,o
int 21h
NOTE
Created by Notein
段地址在 ax,偏移地址在 bx, loop循环次数在 cx
利用段前辍:
assume cs: code
code segment 直接写地址很危险.
mov ax, Offffh
mov ds, ax
mov ax,0020h
mov es, ax 附加段地址寄存器
mov bx,0
mov cx,12
→默认是 ds
s: mov dl,[ bx]
mov es:[ bx], dl
inc bx
loops
mov ax 4c00h
int 21h
code ends
end
在代码段中使用数据
程序中直接写地址很危险.解决办法,在程序的段中存放数据,运行时由操作系统分配空间
assume cs: code →在代码段中定义数据日 code segment dw:定义一个字 dw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
↓ start : mov bx,0 一个字,两个字节 db,定义一个字节
定义标号,指示 mov ax,0
代码开始的 mov cx,8 段前辍代表 dd,定义一个双字
位置 s: add ax, cs:[ bx]. 代码段. CS.
add bx,2
loop s
mov ax,4c00h int 21h 这样用之后.从0开始的就是数据而不是代码了
code ends
end start
NOTE
Created by Notein
在代码段中使用栈
例,利用栈,将程序定义的数据逆序存放
assume cs: codesg 入栈后再依次出栈到原单元中
codes g segment
dw 0123h,0456h,0789h, oabch, odefh, ofedh, ocbah,0987h
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
start: mov ax, cs
mov SS, ax
mov sp,30h
mov bx,o
mov. (x,8
s: push cs:[ bx]
add bx,2
loop s
mov bx.0
mov cx,8
S,: pop cs:[ bx]
add bx,2
loop s,
把数据,代码,栈放入不同的栈
上一个代码内,都在一个段中,程序显得混乱
改: assume cs: code, ds: data,SS: stack.
DS:0
data segment
dw ·入栈: mov bx,o
数据段
data ends mov cx,8
stack segment s: push [ bx] 默认 ds
dw 0,0…. 0 add bx,2
SS:0
stack ends.
栈段
code segment loop s
start: mov ax, stack.
mov Ss, ax 出栈: mov bx,o
CS:0
mov sp, 20h mov cx.8
代码段
mov ax, data So: pop [ bx]
mov ds, ax add bx.2
loop So
NOTE
Created by Notein
内存寻址
处理字符问题:汇编中,用单引号‘字符’的方式指明数据是字符,编译器将把它们转化为相应的ASCII码 (在汇编中为16进制的A:41a:61)小写字母的ASC11码比大写的值大2041,A:01000001 a:01100001
大小写转换的问题
assume cs: codesg, ds: datasg
mov bx,0
datasg segment
mov cx,5
db’BaSiC’
s: mov al,[ bx]
db ‘iNfOrMaTiOn’
and al,11011111b
datas g ends
mov[ bx], al
inc bx
codes g segment
loop s
start:
mov bx,5
mov ax, datasg
mov ds, ax
mov cx,11
;第一个字符串 : 小写字母转换为大写字母
s0: mov al,[ bx]
;第二个字符串: 大写字母转换为小写字母
or al,00100000b
mov ax,4c00h
mov[ bx], al
int 21h
inc bx
codesg ends
loop s0
end start
[bx+idta]方式寻址
表示一个内存单元
NOTE
Created by Notein
含义 mov ax,[ bx+200]类比数组实现
将一个内存单元的内容送入 ax,这个内存单元长度为2字节,存放1个字.
(ds)⁺16
其他表示方法
ds)⁴/6+200→[200]
mov ax,[200+bx]
( bx)
mov ax,200[ bx]
[ bx+200] ds×16+200+( bx)
mov ax,[ bx].200
SI和DI寄存器(变址寄存器)
常执行与地址有关的地址,是与 Bx功能相近的寄存器
SI:源变址寄存器, 区别:SI和DI不能分成两个8位寄存器来使用
DI:目标变址寄存器
注: dalasg segment
db’ welcome to masm!”
db’…预留出一定空间,点的数跟字符串一样,16个,10
[bx+sin]和[ bx+di]方式寻址
d3% bx称为基址
ds16+( bx)
Si
si称为变址
ds1b+( bx)+( si)
其他写法: mov ax,[ bx][ si]
NOTE
Created by Notein
[bx+Si+idata]和[bx+di+idata]
ds*/6
ds16+( bx)
(ax)=(ds)^{ \ast }/6+(bx)+(5i)+idata)
( si)
写法: [ bx+200+si]
ds16+( bx)
idata利基数.常数
+( si)
200[ bx][ si]
as×16+( bx)+( si)+idota
[ bx].200[ si]
[[ bx][ si]].200
例:2000:1000 BE 00 06 00 6A 22······
mov ax,2000Hax=2000H
mov ds, axds=2000H
mov bx,1000H bx=1000H
si=0
mov si,0
mov ax,[ bx+2+ si]ax=0006
inc si Sizl
mov cx,[ bx+2+ si]Cx=6A00
inc si si=2
mov di, sidi=2
mov ax,[ bx+2+ dilax=226A
NOTE
Created by Notein
不同的寻址方式的灵活应用
形式 名称 特点 意义 示例
[ idata] 直接寻址 用一个常量/立即数 用于直接定位一个内
来表示地址 存单元 mov ax, [200]
寄存器间 用一个变量来表示内 用于间接定位一个内 mov bx,0
[ bx] 接寻址 存地址 存单元 mov ax, [ bx]
用一个变量和常量表 可在一个起始地址的
[ bx+ idata] 寄存器相 基础上用变量间接定 mov bx,4
对寻址 示地址 位一个内存单元 mov ax,[ bx+200]
基址变址 可以处理类似工维数组的数据[ bx+ si] 寻址 用两个变量表示地址 mov ax, [ bx+ si]
[ bx+ si+ idata] 相对基址 用两个变量和一个常 mov ax, [ bx+ si+200]
变址寻址 量表示地址
例:将database中每个单词改为大写字母.(二重循环问题)
assume cs: codesg, ds: datasg
mov ax, datasg
法1.
datas g segment
mov ds, ax
mov bx,0
外层循环次数
db’ ibm
mov cx,4
将外层循环的 cx
db’ dec
s0: mov dx, cx
值保存在 dx中
db’ dos
mov si,0
设置为内存循环次数
mov cx,3
db’ vax
s: mov al,[ bx+ si]
datas g ends
and al,11011111b
mov[ bx+ si], al
codes g segment
inc si
loop s
start:
add bx,16
→回复外层(x
codes g ends
mov cx, dx
end start
loop s0
法2.若其他寄存器也被占用
用固定的内存空间保存数据,
movdx,x→moVdx:40H,c
法了,用找保存数据, mov dx,cx→push(x, pop(x
NOTE
Created by Notein
内存的寻址方式
寻址方式 含义 名称 常用格式举例
[idata] EA= idata;SA=(ds) 直接寻址 [idata]
[bx] [si] [di] [bp] EA=(bx);SA=(ds) EA=(si);SA=(ds) EA=(di);SA=(ds) EA=(bp);SA=(ss) 寄存器间接寻址 [bx]
[bx+ idata] [si+ idata] [di+ idata] [bp+ idata] EA=(bx)+ idata;SA=(ds) EA=(si)+ idata;SA=(ds) EA=(di)+ idata;SA=(ds) EA=(bp)+ idata;SA=(ss) 寄存器相对寻址 用于结构体: [bx]. idata 用于数组: idata[si], idata[di] 用于二维数组:[bx][idata]
[bx+ si] [bx+ di] [bp+ si] [bp+ di] EA=(bx)+(si);SA=(ds) EA=(bx)+(di);SA=(ds) EA=(bp)+(si);SA=(ss) EA=(bp)+(di);SA=(ss) 基址变址寻址 用于二维数组:[bx][si]
[bx+ si+ idata] [bx+ di+ idata] [bp+ si+ idata] [bp+ di+ idata] EA=(bx)+(si)+ idata; SA=(ds) EA=(bx)+(di)+ idata; SA=(ds) EA=(bp)+(si)+ idata; SA=(ss) EA=(bp)+(di)+ idata; SA=(ss) 相对基址变址 寻址 用于表格(结构) 中的数组项: [bx]. idata[si] 用于二维数组: idata[bx][si]
用于内存寻址的寄存器印
BP:也是基址寄存器,只有 bx, bp, si, di可以用在[…]对内存单元寻址
mov ax,[ Cx] ax. dx, cx, ds.这样的用法都是错误的
mov ax,[a]
bx以外的通用寄存器,段寄存器,不可以用在[···]中
一般组合
基址 变址
si
\max ,[bx+bP] \atop mov \cos ,[ \sin +d] }错误的用法
bp
di
bx默认 ds段 有指定用指定,没有就默认.
bp 默认 ss段
NOTE
Created by Notein
汇编语言中数据位置的表达
1、立即数( idata ) 2、寄存器
对于直接包含在机器指令中的数据,称为立即数( idata) , 数据包含在指令中
指令要处理的数据在寄存器中, 在汇编指令中给出相应的寄存器名。
3、内存:段地址( SA) 和偏移地址( EA)指令要处理的数据在内存中, 由SA:EA确定内存单元。
mov ax,[0] mov ax,[ bp]
mov ax, bx mov ax,[ di]movax,[bp+8]
mov ax,1 mov ds, ax mov ax,[ bx+8]movax,[bp+si]
add bx,2000h mov ax,[ bx+ si]
push bxmovax,[bx+sin+8] movax,[bp+sin+8]
or bx,00010000b mov ds:[0], bx 段地址默认在 ds中 段地址默认在 ss中
mov al,’a’ push ds
mov ax, ds:bp=(ds)^16+(bp))
073F:0100 mov ax, 1 mov ss, ax
073F:0103 mov ax, es:bx=(es)^16+(bx))
-u 073f :0100 mov sp, ax mov ax, ss:[ bx+ si] : ( ax)=(( ss)*16+( bx)+( si))073F:0100 B80100 MOU AX,0001
读是00°| mov ax, cs:[ bx+ si+8] : ( ax)=(( cs)*16+( bx)+( si)+8)
显性的给出存放段地址的寄存器
指令要处理的数据有多长? 用行动或 bytention指挥
字 word操作 字节 byte操作
mov ax,1 16位 mov al,1 8个位
mov bx, ds:[0] mov al, bl
mov ds, ax mov al, ds:[0]
mov word ptr ds:[0],1 inc word ptr [bx] inc word ptr ds:[0] add word ptr [bx],2 mov byte ptr ds:[0],1 inc by te ptr [bx] inc byte ptr ds:[0] add byte ptr [bx],2
在没有寄存器参与的内存单元访问指令中,用 word ptr或 by te ptr显性地指明所要访问的内存单 元的长度是很必要的,否则, CPU无法得知所要 访问的单元是字单元 , 还是字节单元。
mov ds:[0], ax mov ds:[0], al
inc ax inc al
add ax,1000 add al,100
可以通过“。”将立即数写到[]外面
[ bx+sifidata]: bx定位整个结构体.即存放数据的地方
s;定位数据项中的元素
idata定位结构体中的某一个数据项
类比C语言:
struct Player{ struct Player yao={ 3.
char name[3]; yao. team[i]中
char birthday[9]; ↓ si就类似于 for循 si
int num bx idata 环中的 int i, it+
char team[3];};
NOTE
Created by Notein
div指令实现除法
被除数:(默认)放在 Ax或 Dx和 Ax中
除数:8位或16位,在寄存单元或内存单元中 放高位 放低位
11
格式: 被除数 AX DX和AX
div 寄存器 div内存单元 除数 8位内存或寄存器 16位内存或寄存器
商 AL AX
低位放商,高位放余 余数 AH DX
示例指令 被除数 除数 商 余数
div bl 8位寄存器 ( ax) ( bl) ( al) ( ah)
div byte ptr ds:[0]( 8位 ( ax) (( ds)*16+0) ( al) ( ah)
div byte ptr[ bx+ si+8] ( ax) (( ds)*16+( bx)+( si)+8) ( al) ( ah)
div bx 16位 ( dx)*10000H+( ax) ( bx) ( ax) ( dx)
执行除法前,可以将 ax, bx中的值先存入一个固定的单元或入栈,之后再取出,确保执行 div之前 ax. bx内是除数
div word ptr es:[0] ( dx)*10000H+( ax) (( ds)*16+0) ( ax) ( dx)
div word ptr [ bx+ si+8] ( dx)*10000H+( ax) (( ds)*16+( bx)+( si)+8) ( ax) ( dx)
切记提前在默认的寄存器中设置好被除数, 且默认寄存器不作别的用处。
指令示例:
利用除法指令计算100001D/100D,
10000D= \enclose{circle} {86A}/H,需要进行16位除法(位数除了由除数决定,被除数过大也需要16位)
低存 ax
高存 dx bx存放100D=64H
mo y dx,1 db 1; 01H
mov ax,86A1 mov bx,64 dw 1;0001H
div bx ddl;0000 0001H
dup设置内存空间
功能: dup和 db,dw. dd女数据定义伪指令配合使用,来进行数据的重复
指令 功能 相当于
db 3 dup (0) 定义了3个字节, 它们的值都是0 db 0,0,0
db 3 dup (0,1,2) 定义了9个字节 , 由0、1、2重复3次构成 db 0,1,2,0,1,2,0,1,2
db 3 dup (‘abc’,’ ABC’) 定义了18个字节 , 构成’abcABCabcABCabcABC’ db‘abcABCabcABCabcABC’
NOTE
Created by Notein
流程转移与子程序
转移:
一般情况下是顺序地逐条执行,而在实际中,常需要改变程序的执行流程
按转移行为
段内转移;只修改iP,如 gmp ax
段间转移:同时修改CS:1P,如 jmp 1000:0
根据指令对IP修改的范围不同
段内短转移:|P修改范围为-12812732767
段内近转移:|P修改范围为:-32768
按转移指令
无条件转移指令(如jmp)
条件转移指令(如jcx2)
循环指令(如: loop)
过程
中断
操作符 off set
取得标号的偏移地址
格示: offset 标号
例: mov ax, offset start
练习
二问题: 有如下程序段, 添写2条指令, 使该程序在运行中将s处的一条指令复制到s0处
assume cs: codesg
codes g segment
s: mov ax, bx
mov si, offset s
mov di, offset s0
mov ax, cs:[ Si]
mov cs:[ di], ax NOTE Created by Notein
s0: nop
nop
codes g ends
ends
; nop的机器码占一个字节, 起“占位”作用
jmp指令
无条件转移
段间转移(远转移):jm p 2000:1000
段内短转移: j mp short 标号.8位位移
段内近转移: jump near ptr标号 16位位移
是依据位移进行转移
例 start: mov ax,o 移动0003
- jmp shorts→当前iP:0005
add ax.1 =0008
s : incax )位置:0008
它所携带的内容是转移的位移(即2者间的相对位置)
jmp short 标号:
(1P)=(1P)+8位位移→标号处地址-jmp指令后第一个字节地址;
jmp near ptr 标号
(1P)=(IP)+16位位移.
jump far pir标号.直接得到目的地址,包含了段地址 cs和偏移地址IP
指明了跳转到的目的地址
jump near ptr标号:指明了相当于当前IP的转移位移
jump 16位罚存器 IP=(16位寄存器)
转移地址在内存里
jmp word ptr 用于段内转移,存放一个字,是转移目的的偏移地址
例: mov ax,0123H mov ds:[0], ax jump word p lr ds:[0]IP=0123H
Created by Notein
j mp dword ptr 段间转移,
放两个字,00(1P)高地址是目的地址,低地址是偏移地址
12(cs)
mov ax,0123H
mo v ds[o], ax 执行后(CS)=0
mov word ptr ds:[2],o(2P)=123H
jump dword pt r ds[o]
jmp指令小结 51CTC
jmp指令格式 示例
jmp标号 - 段间转移( 远转移) : j mp far ptr标号 - 段内短转移 : j mp short标号 ;8位的位移 - 段内近转移: j mp near ptr标号 ;16位的位移
jmp寄存器 - j mp bx;16位的位移
jmp内存单元(表示跳转到的地址) - 段内转移: j mp word ptr 内存单元地址 ; j mp word ptr[bx] - 段间转移: j mp dword ptr 内存单元地址 ; j mp dword ptr[bx]
其他转移指令
jcx2指令 (里面保存的是位移)
如果(Cx)=0,则转移到标号处执行,(1P)=(1P)+8位位移
当(cx)≠0,什么也不做 地址
所有有条件转移指令都是短转移,1P_{3e}^{++}围-120∼127,包含的是位移不是
Coop指令
(1)(x)=(cx)-1
(2)当(x)≠0,移到标号(1P)=(1P)+8
2(cx)=0,向下执行
Created by Notein
Call指令和 ret指令
Call指令:调用子程序(即调用函数)
ret指令:返回 都要修改IP.或同时修改CS和IP
例 movax,o
calls
mov ax,4cooh
int 21h
S: add ax.1
ret
格式: call 标号①将当前1P压入栈②移到标号处
(1P):(1P)+16位位移→“标号”处地址— call指令后的第一个字节的地址编译时由程序算出
call far ptr标号,实现的是段间转移.
(1)(SP)=(SP)-2
((SS)×16+(SP))=(CS)
(SP)=(SP)-2
(SS)×16+(SP)=(1P)
(2)((s)二标号所在的段地址
(1P):标号所在的偏移地址
相当于
push cs
push IP
jump far ptr标号
在寄存器中的:格式: call 16位寄存器 (少用)
相当于 push IP, jmp 16位寄存器
Created by Notein
在内存中.
call word p ir内存单元地址 相当于 push IP jump word pir例:
mov sp,10h
mov ax,0123h 减2
mov ds:[0], ax
call word ptr ds:[0]
执行后 , (IP)=0123H , ( sp)=0EH
call dwo dword ptr 相当于 push cs push IP jump dword ptr
mov sp,10h
mov ax,0123h
mov ds:[0], ax 减4字节
mov word ptr ds:[2],0 西个字
call dword ptr ds:[0]
执行后,(CS)=0,(IP)=0123H,(sp)=OCH
取高 取低
ret
用栈中数据,修改IP内容.实现近转移
1 assume cs: codesg, ss: stack
2日 stack segment
3 db 16 dup (0) 子程序的栈
4 stack ends
5日 codes g segment
6 mov ax,4c00h
7 int 21h
8日 start: mov ax, stack NOTE Created by Notein
10 mov sp,16
11 mov ax,0
12 push ax
13 mov bx,0
14 ret →CP=ax=0
15 codes g ends
16 end start
retf
用栈中数据修改CS和1P的内容.
Do P 1P, pop cs
1 assume cst: codesg, ss: stack
2日 stack segment
3 db 16 dup (0)
4 stack ends
5日 codes g segment
6 mov ax,4c00h
7 int 21h
8日 start: mov ax, stack
9 mov ss, ax
10 mov sp,16
11 mov ax,0
12 push cs
13 push ax
14 mov bx,0
15 retf
16 codes g ends
17 end start
NOTE
Created by Notein
Call和 ret自 配合使用1 assume cs: code
2 code segment
3日 main: …
4
call sub1 ;调用子程序sub1…
5
6 mov ax, 4c00h
7 int 21h
8
9日sub1: … ;子程序sub1开始10 call sub2 ;调用子程序sub111 …
12 ret ;子程序返回
13
14日sub2: … ;子程序sub2开始15 …
16 ret ;子程序返回
17 code ends
18 end main
例:计算Z的N次方,N由 Cx提供 assume cs: code, ss: stack
assume cs: code stack segment 明确定义一个栈
code segment 但是这种写 db 8 dup(0)
start: mov ax,1 法是不安全的 db 8 dup(0)
mov cx,3 错误的 stack ends 正确写
call s code segment 法
mov bx, ax start: mov ax, stack
mov ax 4c00h mov ss, ax
int 21h mov sp,16
s: add ax, ax mov ax,1000
loops →由(x决定 calls
ret mov ax,4c00h
code ends int 21h
end start s: add ax, ax
ret NOTE Created by Notein
code ends
乘法 mul指令 end
8位乘法 16位乘法
被乘数(默认) AL AX
乘数 8位寄存器或内存字节单元 16位寄存器或内存字单元
结果 AX DX ( 高位 ) 和AX ( 低位)
例 mul bl –(ax)=(al)(bl) mul by te ptr ds:[0] 一个字节 –(ax)=(al)((ds)16+0) 8位乘法 mul word ptr [bx+ si+8] 16位乘法 提前放被 集数. (ax)=(ax)((ds)16+(bx)+(si)+8)结果的低16位 ; (dx)=(ax)((ds)*16+(bx)+(si)+8)结果的高16位 ;
例100乘10. 100乘10000 做16位乘法
mov al,100 mov ax,100
mov bl,10 mov bx,10000
mul bl mul bx
( ax)=1000(03E8H) ( dx)=000FH,( ax)=4240H
模块化程序设计
参数和返回值问题:用寄存器返回参数(最常用)
用内存单元进行参数传递
用栈传递参数
例:计算 data段中的第一组数据的了次方,结果保存在后面一组dword中
assume cs: code
data segment 循环8次
dw 1,2,3,4,5,6,7,8
分空间 ddd 0,0,0,0,0,0,0,0 s: mov bx.[ si]取] 求3次方
cube: mov ax, bx mul bx mul bx ret
data ends
code segment mov
start: mov ax, data 高比您 mov[ di].2, dx
mov ds, ax add si,2→取下一个字2
mov si,0 mov di,16 add di,4》高低共4个字节.走8次
;循环处理 loop s
mov ax,4c00h C:> debug p10-5. exe g
int 21h Program terminated normally
code ends -d 076a:0 2f
076A:0000 01 00 02 00 03 00 04 00-05 00 06 00 07 00 08 00
end start 076A:0010 076A:0020 01 7D 00 00 00 00 08 D8 00 00 00 00 00- 人 1B 04 00 01 00 2 00 40 0、 20 ✗ 00 00 NOTE
Created by Notein
用内存单元批量传递数据
将批量数据放到内存中.然后将它们所在内存空间的首地址放在寄存器中,传递给需要的子程序,返回结果同理
用栈传递参数 difcube : push bp- →为了避免 bp原数据丢失
mov bp, sp
mov ax,[ bp+4];将栈中a的值送入 ax中
sub ax,[ bp+6];减栈中b的值
返回值在 mov bp, ax
dx, ax mul bp ret n含义
mul bp pop ip
pop bp add sp,n
ret 4
寄存器冲突问题
db’ conversation’,o这样写的话,可以没有读到0时做出相应的行为,读到10就代表结束
assume cs: code ;再例将以下字符串转为大写
data segment assume cs: code
db’ conversation’,0 data segment
data ends
code segment db ‘ word’,0
start: mov ax, data 设置起始地址 db ‘ unix’,0
mov ds, ax db ‘ wind’,0
mov si,0 并调用子程序
call capital db ‘ good’,0
mov ax,4c00h data ends
int 21h code segment
capital: mov cl, [ si] 当[s]=0. start: mov ax, data
mov ch,0 mov ds, ax
jcxz okch+d=cx=0, mov bx,0
)循环数 and byte ptr [ si], 11011111b mov cx,4
inc si s: mov si, bx
jmp short capital 跳转 NOTE ok: ret call capital IN Created by Notein
code ends loop s 公反生
end start mov ax,4c00h 冲突
int 21h
寄存器冲突问题解决 capital: mov cl,[ si] 读取数据
mov ch,0
①在编写的时候注意看看子程序中有没有用到会冲突的寄存器.
jcxz ok
and byte ptr [ si],11011111b
inc si
②编写时不使用会产生冲突的寄存器 jmp short capital
ok: ret
code ends
③子程序标准框架 end start
子程序开始:子程序中使用的寄存器入栈
子程序内容
子程序使用的寄存器出栈
返回( ret. retf)
由此,解决方案为:在子程序开始,将要用到的寄存器中的内容都保存起来,在子程序返回前再修复
因此,上述的代码做如下修改
capital push cx push si
change: mo v cl,si
mov ch,0
jcx2 ok
add by te plr[ si],//011111b
inc si
jump short change
ok: pop si
pop cx
ret
NOTE
Created by Notein
标志寄存器
PSW/F∠AGS别称:程序状态字.
是一个16位寄存器,按位起作用1、3.5,12,13.14,15不具含义
1.用来存储相关指令的某些执行结果
2.用来为CPU执行相关指令提供行为依据.
3.用来控制CPU的相关工作方式
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=**** ES=SS= CS=****IP=0100 NU UP EI PL NZ NA PO NC
← ↑ ↑ ↑
OF DF SF ZF PF CF
Overflow
Direction
Positive
标志 值为1 值为0 意义
OF OV NV 溢出
DF DN UP 方向
SF NG负 PL非负 符号
ZF ZR 0 NZ那0 零值
PF PE偶 PO奇 奇偶
CF CY NC 进位
Sign / negative
Zero
Parity odd/ even
Carry
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
直接访问标志寄存器的方法. 主要还是由于指令而变化
pushf.将标志寄存器的值压栈
popf:从栈中弹出数据,送入标志寄存器中
ZF:标记相关指令的计算结果是否为0.
结果0,∠F=1,结果1,∠F=0
PF:奇偶标志位,PF记录执行后,结果的所有二进制位中1的个数当1的个数为偶数,PF=1,当1的个数为奇数,PF=0
Created by Notein
SF:符号标志,记录指令执行后,将结果视为有符号数
结果为负,SF=1,结果为非负,SF=0
负数补码,所有数01取反,末位加1
是否带符号,根据具体需求而定,如果数字当无符号数,则SF无意义
CF(进位标志)
在进行无符号数运算的时候. CF记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值
有进位或借位,CF21,无进位借位,CF=0
对于位数为N的无符号数来说↓是第N-1位
OF.溢出标志
在进行有符号数运算的时候,如果超出了机器所能表示的范围称为溢出.
有溢出,OF21,无溢出,OF=0
指令 CF OF SF ZF PF 标志 值为1 值为0 意义
sub al, al 0 0 0 1 1 OF OV NV 溢出
mov al, 10h DF DN UP 方向
add al,90h SF NG负 PL顶负 符号
mov al, 80h
ZF ZRo NZ非。 零值
add al, 80h
PF PE偶 PO奇 奇偶
mov al, OFCh
CF CY NC 进位
add al, 05h
mov al 7Dh
add al, OBh
NOTE
Created by Notein
带进位(借位)的加(减)法
adc,带进位加法,利用了CF位上记录的进位值
格式: adc 操作对象),操作对象2
操作对象|=操作对象|+操作对象2+CF
(ax)=(ax)+(bx)+CF
例: mov al,98H
addal,al →al=30H. CF=|有进位
adc al,3 →al=30+3+CF=34
例2: mov ax,1
addax,ax→ax=2,cF:0
adc ax,3 →( ax)=( ax)+3+cF=5
例3: mova x,2
mov bx,1
sub bx, ax CF=1
adc ax,1 ( ax)=2+1+cF=4 ax高, bx次高, cx,低
应用,大数相加 1EF0001000H+2010001EF0H
先将低16位相加,然后将高16位和进位值相加 mova x,001EH
mov ax, 001EH 计算1EF000H+201000H mov bx,OFooOH
mov bx,oFoooH ax高16, bx低16位 mov (x,1000H
add box,1000H 001E F000H add cx,lEFoH
adc ax,0020H +)0020/000H adc bx,10004
adc ax,0020H
汇编源称序中,数据不能以字母开头,要在前面加0
NOTE
Created by Notein
671E 0F04 54F6 8B7A 0A8E 78E6 A8F5 A452H 逆序存放
+)0452 58F5 78E6 0A8E 8B7A 54F6 EF04 E71EH ).
清除进位OF ???
code segment ;寄存器压栈 push ax
start : mov ax, data sub ax, ax/ push cx
mov ds, ax s: mov ax,[ si] push si
mov si,0 adc ax,[ di] push di
mov di,16 mov[ si], ax
mov cx,8 inc si }换成c 免成 add di,2,会改变CF
call add128 inc si
mov ax,4c00h inc di
int 21h inc di pop di
3换成c loop s pop si
;定义子程序 ;寄存器出栈 pop cx
code ends ret pop ax
end start
sbb,带借位减法
格式: sbb 操作对象1,操作对象2
功能:操作对象|二操作对象|一操作对象.2-CF
(ax)=(ax)-(bx)-CF
003E 1000H mov bx,1000H
-)0020 2000H_ moV aX,003EH
sub bx,200oH →CF=1
sbb ax,0020H
NOTE
Created by Notein
cmp与条件转移指令
cmp:
格式: cmp 操作对象1,操作对象2,是比较指令,结果不保存,
功能:计算操作对象1一操作对象2 用于影响标志指令
例 cmp ax, ax
ZF=1PF=1,SF=0,CF=0,OF=0
movax,8}2F=0,PF=0,PF=0CF=0OF=0F=0
比较关系 (ax) ? (bx) (ax)-(bx)特点 标志寄存器
等于 (ax)=(bx) (ax)-(bx)=0 ZF = 1
不等于 (ax)≠(bx) (ax)-(bx)≠0 ZF = 0
小于 (ax)<(bx) (ax)-(bx)将产生借位 CF = 1
大于等于 (ax)≥(bx) (ax)-(bx)不必借位 CF = 0
大于 (ax)>(bx) (ax)-(bx)既不借位, 结果又不为0 CF = 0且ZF = 0
小于等于 (ax)≤(bx) (ax)-(bx)或者借位, 或者结果为0 CF =1或ZF =1
比较指令的设计思路, 即: 通过做减法运算影响标志寄存器, 标志寄存器的相关位的取值, 体现比较的结果。
条件转移指令 jxx×标号
根据单个标志位转移的指令
指令 含义 测试条件
je/ jz 相等/结果为0 ZF=1
jne/ jnz-nwt 不等/结果不为0 ZF=0
js 结果为负 SF=1
jns 结果非负 SF=0
jo 结果溢出 OF=1
jno 结果溢出 OF=0
jp 奇偶位为1 PF=1
jnp 奇偶位不为1 PF=0
ib/ inae/ ic 低于/不高于等于/有借位 CF=1
NOTE
Created by Notein
jnb/ jae/ jnc 不低于/高于等于/无借位 CF=0
jxx指令和 cmp指令配合实现 if语句功能
条件转移指令应用
实现双分枝结构:
cm p ah, bh if(a==b) a=a+a;
je s else a=a+b;
add ah, bh
jmp short ok
S: add ah, ah
ok: ret
多数情况下 jxx)前有 cmp,但不是必须
DF标志和串传送指令
start: mov ax, data data segment
mov ds, ax db’ Welcome to masm!
mov si,0
mov di,16 db 16 dup(o)
mov cx,8 data ends
s: mov ax,[ si]
mov[ di], ax
在串处理指令中,控制每次操作后 si, dì的递减
add si,2
add di,2DF=0;每次操作后 si, di递增
loop sDF=1每次操作后 si. di递减
mov ax,4c00h
int 21h
code ends
end start
NOTE
Created by Notein
串传送指令
movsb:s-slring b-byte movsw : w-word
以字节为单位传送 以字为单位传递
(1)(es)×16+di)=((ds)×16+(s)) (1)(es)×16+(di))=(1ds)×16+(si))
(2)若DF=0,则( si)=( si)+1 (2)若DF=0,则( Si)=( si)+2
(di)=(di)+1 (di)=(di)+2
若DF=1,则(S₁)=(Si)-1若DF=1.则(Si)=(Si)-2
(di)=(di)-1 (di)=4i)-2
Cld指令:DF设为0( clear)
std指令:DF设为1 ( set up)
rep指令
根据 Cx的值重复执行后面的指令
rep movsb⇒ S: movsb
loops
NOTE
Created by Notein
中断及外部操作
移位指令
moval,01001000b 左
逻辑左移 SHL OPR, CNT shla l,1 循环左移 ROL OPR,CNT
al→10010000b
会影响CF
CF
右移
OPR
CF
OPR
逻辑右移 SHR OPR,CNT 操作为末位补0 循环右移 ROR OPR,CNT 操作为首位去末位
循环
CF
OPR
CF
算术移动
算术左移 SAL OPR, CNT 算术右移 SAR OPR,CNT
最高位不变
CF
OPR
CF
带进性
带进位循环左移 RCL OPR,CNT 带进位循环右移 RCR OPR, CNT
CF
OPR
OPR
CF
把OF的原有值补位
逻辑位移指令 shl和 shr
SHL OPR,CNT,将 OPR逻辑左移CNT位
(1)将寄存器中的数据向左移位
(2)将最后移出的一位写入CF中
(3)最低位用0补充
操作显存数据
显存地址空间128KRAM A0000BFFFFBFFFh共32K,80*25彩色字符模式
其中B8000h
描述内存单元的标号
code segment
a d b 1,2,3.4.5,6.7.8 mov al,a[ si]
Created by Notein
在 code段中使用标号a,b,后面没有“:”,它们同时描述内存地址和单元长度的标号
最常见的方式,数据段中的数据标号
数据的直接定址表
数值+30h=对应字符的ASC11值
数值+37h=对应字符的ASCll值,
102/50Ah+37h=“A’的ASC11值
用查表的方式解决问题
table db’0123456789ABCDEF’;字符表
利用表在两个数据集合之间建立一种映射关系,用查表的方式根据给出的数据得到其有另一集合中的数据
NOTE
Created by Notein
来源: https://www.yuque.com/guansuanbangzhuangganjun/oxmbxg/xdmw348756hrf3tv
语雀文档ID: 196654840