汇编16位

寄存器

段寄存器

代码段寄存器CS(Code Segment)
存放当前正在运行的程序代码所在段的段基址,表示当前使用的指令代码可以从该段寄存器指定的存储器段中取得,相应的偏移量则由IP提供。
数据段寄存器DS(Data Segment)
指出当前程序使用的数据所存放段的最低地址,即存放数据段的段基址。
堆栈段寄存器SS(Stack Segment)
指出当前堆栈的底部地址,即存放堆栈段的段基址。
附加段寄存器ES(Extra Segment)
指出当前程序使用附加数据段的段基址,该段是串操作指令中目的串所在的段。

DS:存放要访问数据的段地址,8086CPU不支持将数据直接送入段寄存器,所以可以用其他寄存器中转,取得是2字节(字)
SS:SP栈的段地址/偏移地址, SS不支持将数据直接送入段寄存器,T命令执行SS指向的指令时,下一条指令也紧接着执行
CS/ IP:代码段寄存器(段地址)/ 指令指针寄存器(偏移地址)Cs*16+n=物理地址
CPU将CS,IP中的内容当做指令的段地址和偏移地址,用他们合成指令的物理地址,到内存中读取指令码

标志寄存器

作用
存储相关指令的某些执行结果
为CPU执行相关指令提供行为依据
控制CPU的相关工作方式
8086CPU的标志寄存器有16位,其中存储的信息称为程序状态字(PSW)
每一位都有专门的含义,1,3,5,12~15没有使用

DEBUG中的表示
标志 值为1的标记 值为0的标记
Of OV NV
Sf NG PL
Zf ZR NZ
Pf PE PO
Cf CY NC
Df DN UP

第六位ZF,零标志位,记录相关指令执行后,结果是否为0,如果为0,ZF=1,否则ZF=0
Mov ax,1 sub ax,1 执行后结果0,则ZF=1

第二位PF,奇偶标志位,记录相关指令执行后,所有bit位中1的个数是否为偶数,如果为偶数,PF=1,否则=0

第七位SF,符号标志位,记录相关指令执行后,结果是否为负,如果为负,=1否则=0

第零位CF,在进行无符号数运算,记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值
Mov al,98H
Add al,al ;AL=30H,CF=1,CF记录了更高有效位向更高位的进位值
Add al,al ;AL=60H,CF=0

Mov al,97h
Sub al,98h ;AL=FFH,CF=1,CF记录了向更高位的借位值,借位后相当于计算197-98

第十一位OF,针对有符号位运算的结果是否发生溢出,如果是OF=1,否则0

第十位DF,方向标志位,在串处理指令中,控制每次操作后si,di的增减
Df=0,每次操作后si,di递增
设置df值
Cld/std:将标志寄存器的df位置0/1
配合使用Movsb/movsw指令

进入debug模式

mount c d:\
c:
debug
cd MASM
cd …
G 0012:执行程序到当前代码段CS:0012h处
P:跳过重复执行的loop, 执行int 21H
R 寄存器名称:修改寄存器值
R:查看寄存器值,以及CS:IP对应的内存地址存放的机器码,以及汇编指令等
D 段地址:起始偏移地址 [结尾偏移地址]:查看内存地址内容,段地址存储在ds
d 1000:0 0 < = = > d 0fff:10 10 < == > d 0100:f000 f000
E段地址:偏移地址 [数据,数据,数据] :改写内存中的内容
空格输入下一个,enter设置完成,可以写入字符串”A”,机器码,数字
E 1000:0 0 1 2 3 4 5 6
U段地址:偏移地址:查看内存的机器码,汇编指令
T:执行CS:IP指向的指令
A:以汇编指令的格式在内存中写入一条机器指令

内存中存储时,内存单位是字节单元(一个单元存放一字节)
一个字需要2字节,所以需要2字节单元存储,字的高/低位字节分别存放在高/低地址单元中.一个字由2,3二个内存单元组成,则字单元的起始地址为2,可称之为2地址字单元
Jmp段地址:偏移地址,偏移地址,作用为:用段地址修改CS,偏移地址修改IP

连接作用

源程序过于大,划分为多个源程序文件来编译,在用连接程序将他们连接,生成可执行文件
程序中调用了某个库文件中的子程序,需要此库文件和该程序生成的目标文件连接
源程序编译后,得到存有机器码的目标文件,还需要连接程序将这些内容处理为最终的可执行信息.

程序加载后,ds存放程序psp的段地址,偏移为0
内存区的前256字节存放psp,dos用来和程序通信,256之后放的是程序
Psp物理地址为ds16+0
程序地址为ds
16+256+0=(ds+16)*16+0,表示为ds+10:0也是CS:IP设置的地址

MASM path/finename.后缀(是asm可省略) ;
Link path/finename.后缀(是OBJ可省略) ;
Debug xx.exe:XX程序进入debug模式,cmd加载debug,debug加载xx,当xx结束时返回到debug,debug返回到cmd

汇编命令

assume cs:codesg
codesg segment

dw 0123h,0456,0789h,0abch,0defh,0fedh,0cbah,0987h //定义字型数据
这8个数据在代码段中,CS存放代码段的地址,因为他们是代码段的最开始,所以偏移地址为0,这8个数据在代码段的偏移0,2…处.CS:[0]…[E]就可以访问,用debug的u命令查看的只是在汇编指令前面用dw定义的数据解析而成的错误指令,d命令就能查看dw定义的数据,
可以在debug加载执行文件后设置ip地址从而越过dw定义数据的位置,从而使cs:ip指向程序中的第一条指令.如果不这样的话,直接运行会出问题,因为程序的入口处是由dw定义的数据解析而成的错误指令,可以再源程序中指定入口所在,在程序开始地方和end处添加start标号

Start:mov ax,0123h
mov bx,0456h
add ax,bx
add ax,ax
inc ax //ax++
dec ax //ax–

mov ax,0ffffh //汇编中数据不能以字母开头
mov ax,2
mov cx,11 //循环次数
s:add ax,ax //标号s代表一个地址,地址有一条指令 add ax,ax
loop s

db ‘a’ ;指明数据以字符形式给出,每个字符占用1字节
dw;表示一个字,占用2字节
dd;表示双字,占用4字节

//程序返回
mov ax,4c00h
int 21H

codesg ends
end start

伪指令:不被CPU执行,由编译器执行的命令
段名 segment/段名 ends:定义一个段,定义多个段的时候,段名可以代替段地址,而偏移地址就要看它在段中的位置

end:汇编程序结束标记,也可以通知编译器程序的入口在什么地方,指定了入口在start处
assume:假设某一段寄存器(如cs)和程序中某一个用segment…ends定义的段关联
and/or:逻辑与/非运算
div:
除数:有8位和16位二种,存储在寄存器或内存单元中
被除数:默认放在AX/DX和AX,若除数8位,被除数16位,默认AX存放
除数16位,被除数32位,默认DX和AX存放,DX存高16位,AX存低16位
结果:除数若8位,则AL存储商,AH存储余数.
若16位,AX存商,DX存余数
格式:div 寄存器/内存单元
div byte ptr ds:[0]
al=ax/(ds16+0),
ah=ax%(ds
16+0)

div word ptr es:[0]
ax=[dx10000H+ax]/(es16+0)
dx=[dx10000H+ax]%(es16+0)

mul:*
2乘数只能都是8/16位,如果是8位,一个默认al,另一个放在8位寄存器or内存字节单元中.如果16位,一个默认AX,另一个16位寄存器or内存字单元中
结果:8位乘法,默认AX.16位高位DX,低位AX存放
格式
Mul 寄存器
Mul 内存单元
Mul byte ptr ds:[0]
Ax=al*(ds16+0)
Mul word ptr [bx+si+8]
Ax=ax
(ds16+bx+si+8)结果低16位
Dx=ax
(ds*16+bx+si+8)结果高16位

dup:进行数据重复,db/dw/dd 重复次数 dup(重复的字节/字/双字型数据)

Mov 寄存器名,[内存单元地址] :[0],[]表示一个内存单元,0表示内存单元的偏移地址,执行时默认取ds值,作为段地址
汇编程序中mov ax,[0]被编译为mov ax,0,debug中则理解为内存单元[0],可将偏移地址送入bx寄存器,用[bx]方式访问内存单元,如:
Mov bx,0
Mov al,[bx]
也可以在[]前面显示给出段地址ds,cs,ss,es,用于显示指明内存单元的段地址的ds/cs等称为段前缀
Mov al,ds:[0]

ADD/SUB:+/-

PUSH/pop:以字为单位进行,执行时,CPU从SS:SP中获得栈顶地址,入栈时栈顶从高地址向低地址方向增长,8086CPU不会考虑栈上下越界问题

Adc指令
作用:带进位加法指令
格式:Adc obj1,obj2
功能:Obj1=obj1+obj2+CF
如果CF的值是被sub指令设置的,纳闷ADC的含义就是借位值,同理加法进位
加法分2步执行
低位相加
高位相加在加上低位相加产生的进位值
Adc和add指令配合可以对更大的数据进行加法运算

Mov ax,2
Mov bx,1
Sub bx,ax ;1-2需要借位
Adc ax,1 < == > ax=ax+1+CF=2+1+1=4

算出1EF000H+201000H结果
Mov ax,001EH
Mov bx,0F000H
Add bx,1000H
Adc ax,0020H

Sbb指令
带借位减法指令,利用CF位上的记录值
Sbb ax,bx < == > ax=ax-bx-CF

Movsb/movsw:针对字节/字
movsw可以理解为:
Mov es:[di],word ptr ds:[si]
如果df=0
Add si,2
Add di,2
否则si/di-=2
通常和rep使用
Rep movsb可以理解为
S:movsb
Loop s

Pushf/popf:将标志寄存器的值入栈/出栈

Shl/shr:逻辑左/右移指令

  1. 将一个寄存器or内存单元中的数据向左移位
  2. 将最后移出的一位写入CF中
  3. 最低位用0补充
    移动位数>1,需要用cl存储移动位数

Cmp比较指令

相当于减法指令,但不保存结果,仅影响flag寄存器
无符号运算时
Cmp 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可能借位,也可能为0,cf=1|zf=1
Ax>bx,ax-bx不必借位且结果不为0,cf=0&zf=0
ax>=bx,不必借位,结果可能为0,cf=0

有符号运算时
Cmp ah,bh
Sf=1,of=0
Of=0说明没有溢出,sf=1实际结果为负,逻辑上真正结果的正负=实际结果的正负
所以ah<bh

Sf=0,of=0没有溢出且实际结果非负,ah>=bh

如果因为溢出导致了实际结果为负,那么逻辑上真正的结果必然为正
Sf=1,of=1 a>b

与条件转移指令使用
无符号位的比较结果进行转移的条件转移指令
指令 含义 检测的相关标志位
Je(jump equal) 等于则转移 Zf=1
Jne(not) 不等于则转移 Zf=0
Jb(below) 低于则转移 Cf=1
Jnb 不低于则转移 Cf=0
Ja(above) 高于则转移 Cf=0&zf=0
Jna 不高于则转移 Cf=1|zf=1

转移指令

控制cpu执行内存中某处代码的指令,可以修改ip或同时修改CS或IP的指令
只修改ip为段内转移
ip修改范围为-128~127为短转移
-32768~32767为近转移
同时修改CS和IP为段间转移
转移指令分类为:
无条件转移指令(如:jmp)
条件转移指令,都是短转移
循环指令(如:loop) ,都是短转移
过程
中断
offset:取得标号的偏移地址

jmp

Jmp需要2信息
转移的目的地址
转移的距离(段间转移,段内短/近转移)
编译的机器码存储的是相对于当前ip的转移位移
依据位移进行转移的jmp指令
段内短转移:Jmp short 标号
short:,所以ip修改地址范围为-128~127
标号:CS:IP指向的地址
转移位移的计算方法
8位位移=标号处地址-jmp指令后第一个字节的地址
Short:声明此处的位移为8位位移
段内近转移:Jmp near ptr 标号
转移的目的地址在指令中的jmp指令
段间转移:jmp far ptr 标号

转移地址在寄存器中的jmp指令
Jmp 16位寄存器:可以理解为MOV IP,16位寄存器
转移地址在内存中的jmp指令
Jmp word ptr 内存单元地址(段内转移)
从内存单元地址处开始存放一个字,是转移目的偏移地址
Jmp dword ptr 内存单元地址(段间转移)
高地址处的字是转移的目的段地址,低的为转移的目的偏移地址

Jczx

有条件转移指令
Jczx标号 < == >If(cx==0)jmp short 标号

循环指令

loop:cx=cx-1,当cx为0则向下执行

ret/retf

ret:用栈中的数据,修改ip的内容,从而实现近转移
ip=ss*16+sp
sp=sp+2
< == >pop ip

retf:用栈中的数据,修改cs和ip的内容,从而实现远转移
ip=ss16+sp
sp=sp+2
cs=ss
16+sp
sp=sp+2

< == >pop ip,pop cs

Call

执行过程
将当前ip或cs和ip压入栈
转移

依据位移进行转移的call指令
Call 标号(将当前ip入栈后,转到标号处执行指令,段内近地址)
< == > Push ip , jmp near ptr 标号

转移的目的地址在指令中的call指令
Call far ptr 标号:段间转移
< == >Push cs , push ip ,jmp far ptr 标号

转移地址在寄存器中的call指令
Call 16位寄存器< == >Push ip , jmp 16位寄存器

转移地址在内存中的call指令
Call word/dword ptr 内存单元地址

数据处理

处理的数据可在三地方,cpu内部(mov bx,ax/mov bx,1),内存(mov bx,[0]),端口

汇编中数据位置表达

立即数(直接赋值),mov ax,1
寄存器,mov ax,bx
段地址(SA)和偏移地址(EA),mov ax,[0]

寻址方式

直接寻址:[idata]
寄存器间接寻址:[bx]

寄存器相对寻址:[bx+idata]
Mov ax,[bx+200]:内存单元长度为2字节,存放一个字,偏移地址为bx中的数值+200,段地址在ds中,ds*16+bx+200
[200+bx]
200[bx]
[bx].200

基址变址寻址:[bx+si]
Si/di和bx意思差不多,但是只有16位,
[Bx+si/di]
[bx][si/di]

相对基址变址寻址:[bx+si+idata]
[Bx+si/di+idata]:表示一个内存单元,偏移地址为bx+si/di+idata
Bx定位整个结构体,idata定位结构体某一数据项,si定位数组项中的每个元素
格式如下
[bx+200+si]
[200+bx+si]
200[bx+si]
[bx].200[si] < == > c语言表示dec.cp[i]
[bx][si].200

Bx,si,di,bp可以用在[]中寻址,可以单独出现以及组合如下情况
Bx/bp+si/di+idata
[bp],没有显性给出段地址,默认ss中

指令要处理的数据有多长

通过寄存器名指明处理的数据尺寸
Ax/bx:表示字操作
Al/bl:表示字节操作
在没有寄存器名存在下,用word/byte ptr指明内存单元长度
指明指令访问的内存单元是一个字单元
Mov word ptr ds:[0],1
有些指令默认字操作,push

内中断

CPU不再接着向下执行(刚执行完的指令),转去处理特殊信息(CPU外部or内部产生的,这里主要讲内部)
当CPU内部有如下情况发生时,将产生相应的中断信息

  1. 除法错误,比如,执行div指令产生的除法溢出,中断类型码为:0
  2. 单步执行, 中断类型码为:1
  3. 执行into指令,中断类型码为:4
  4. 执行int指令,该指令格式为int N,指令中的n为字节型立即数,是提供给cpu的中断类型码

Cpu用8位中断类型码通过中继向量表找到相应的中断处理程序的入口地址
中继向量表
地址:0000:0000~0000:03FF
可以放256中继处理程序的入口地址,一个中继向量需要2字内存,高地址放段地址,低地址放偏移地址

Cpu检测到TF=1,产生单步中断,引发中断过程

中断过程,由硬件自动完成

  1. 取得中继类型码N
  2. Pushf
  3. TF=0,IF=0
  4. Push cs
  5. Push ip
  6. Ip=n4,cs=n4+2
    中继处理程序编写方式
  7. 保存用到的寄存器
  8. 处理中断
  9. 恢复用到的寄存器
  10. 用iret指令返回

Iret用汇编表示为:
Pop ip
Pop cs
Popf

执行完ss寄存器传送数据的指令后,即便发生中断,CPU也不会响应
将ss,sp的指令连续存放,在此之间CPU不会引发中断过程

端口

访问8位端口用al,16位用ax

外中断

CPU如何知道外设随时都可能到的输入?外中断
外中断源类别

  1. 可屏蔽中断
    是CPU可以不响应的外中断,如果IF=0,则不响应可屏蔽中断
    如果在中断处理程序中需要处理它,可设置IF=1
    外设引发的几乎都是可屏蔽中断
    CLI将IF置0,屏蔽掉“可屏蔽中断”,当可屏蔽中断到来时CPU不响应,继续执行原指令
    而STI 与之相反,STI将IF置1,允许“可屏蔽中断”,中断到来转而处理中断
  2. 不可屏蔽中断
    CPU必须响应的中断,中断类型码固定为2,所以,中断过程中,不需要取中断类型码,

执行过程
 标志寄存器入栈,IF=0,TF=0
 CS,IP入栈
 IP=8,CS=0AH

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值