debug

  1. a 汇编指令

  2. r 查看寄存器

    • r 寄存器
  3. d 查看内存

    • d 段地址:偏移地址 (结尾偏移地址)
  4. t 执行指令

  5. e 修改内存数据

    • e 段地址:偏移地址 数据1 数据2 数据3…

    • e 段地址:偏移地址

      数据 空格 数据 空格(逐个询问)

  6. g执行到结束

寄存器

通用:ax, bx, cx, dx, ip, sp

段:cs(control), ds(data),ss(stack)

系统会自动改动sp,但是不会检测是否越界,无论是栈顶还是栈底,没有这样的寄存器!pop和push只支持字数据

push ax //ax中的数据送入栈,sp-=2
pop ax //从栈顶取出数据送入ax,s注意pop以后sp会改动,但是原来的数据是依然存在的,只是不在栈中而已。

程序

  1. 当常量作为偏移地址的时候,最好加上段前缀,不然会当作把常量的值给寄存器
  2. 在多个segment的程序中,start从code段开始,且不需要初始化cs,但是ds和ss是需要初始化的。
  3. 开始以后ds对应的就是程序的起始地址,ds+100H才是真正的data段起始地址

字符处理

  1. 大写字母+20H = 小写字母(ASCII)
    • 小写转大写 and al, 11011111b
    • 小写转大写or al, 00100000b

寻址

bp,bx称为基址,si、di称为变址 idata是立即数 。要么单独用,要么基址变址,要么加个立即数,没有基址基址,没有变址变址,没有立即数立即数。注意bp默认是ss段

mov ax,[200+bx] 

mov ax,200[bx]

mov ax,[bx].200

mov ax,[bx+si]

mov ax,[bx].200[si]

mov ax,\[bx][si].200

mov ax,\[bx][si]

mov ax,[bp+si]

变址寄存器

si di可以和bx类似的寻址用法,不同的是,si di只能作为16位来用,而bx可以拆开

dup

伪指令,用来数据重复

db 3 dup(0)
db 3 dup(0,1,2)
db 3 dup('abc', 'ACB')
db 200 dup(0) ; 定义栈段

转移指令

首先认识一下offset,在程序中用s来作为标号(例如start之类的就是标号),offset s可以取出s的地址。

转移

jmp

这是z
jmp 1000:3 //cs为1000,ip为3
jmp 4 //修改ip为4

jcxz

  1. 有条件转移指令,当cx为0跳转,否则继续下一步。

  2. 短转移,机器码保存的是位移,范围是-128-127

loop

  1. cx减一,然后判断cx是否为0,如果不是,则跳转,否则继续向下执行。

  2. 短转移,负数用补码

  3. 双重循环的时候需要注意,cx的值会被你改变了,所以可以用dx来保存cx的值,或者拿一个内存空间来保存cx,或者拿一个栈,push+pop来保存cx,建议用栈。

call

  1. call + 标号(相对地址 16位)
  2. 将当前的ip或者cs ip压栈(pop cs pop ip)
  3. 跳转,最后通过ret返回
  4. call far ptr段间转移
  5. call + 寄存器
  6. call word ptr ds:[0]
  7. call dword ptr ds:[0]

ret

  1. ret的本质是从栈内取出ip的值,所以即便没有call,也可以去ss sp指向的位置取数据,相当于pop ip
  2. retf段间转移pop ip然后pop cs

寄存器冲突

模块化设计中,由于子程序可能修改原程序的寄存器,所以需要在开始时将寄存器入栈,最后再出栈。

标志寄存器

8086中,标志寄存器是16位的,但没有全用。。1,3,5,12-15没有用。

会影响标志寄存器的:加减乘除与或(运算指令)

不影响的:mov push pop(传送指令)

具体来看几个标志

奇偶: 结果中1的个数为o数时,pf为1,否则为0

符号:将结果视为有符号数,若为负数,sf为1

进位:将数据视为无符号数,有进位或者借位的时候cf为1

溢出:将数据视为有符号数,若有溢出,则of为1

指令系统

传送指令

MOV

MOV DST SRC

  1. dst不能是cs
  2. dst不能同时为内存单元,也不能同时为段
  3. 立即数不能直接送段,要通过ax

XCHG

XCHG OPER1,OPER2

  1. 不影响标志位
  2. 不能用段寄存器
  3. 不能同时为内存单元

LEA

LEA REG,SRC 将偏移地址送入寄存器,也可以用mov ax,offset 标号,来传送地址

  1. 不影响标志位

  2. REG不能为段寄存器

  3. SRC是寻址方式

  4. 32送16时,取低16位

  5. 16送32时,0扩展

LDS

LDS REG,SRC 将src处的内存单元里的数据送入reg(通常为si),并且把src+2的数据送入ds

LES

LES REG,SRC 同上,si换成di,ds换成es

算术指令

加法指令

add adc inc

  1. 其中adc会加上cf,inc是加一

  2. 只有inc不影响标志位

这里考虑一下双精度两个数的加法

add ax,cx
adc dx,bx ;这里要用adc!

减法指令

sub dst,src减法

sbb dst,src带借位减法

dec opr减一

以上几个和加法类似


neg opr求补,求补码,相当于0-opr,所以neg可以求负数的绝对值

cmp opr1,opr2比较

需要注意的是,加法减法的dst和src要求和mov一样。另外,sbb和adc主要用于双精度,对于高位的运算

乘法指令

MUL 无符号数

IMUL 带符号数

  1. 只影响cf,of
  2. 对于mul,当乘积高一半是0时,cf、of都是0,否则都是1
  3. 对于imul,当乘积高一半时低一半的符号扩展时,cf、of是0,否则是1

格式:

​ mul reg

​ mul 内存单元(需要加word ptr等指定数据类型)

​ 不能是mul idata

结果:

​ 存放在ax或dx、ax中

除法指令

基本同乘法

另外需要说一下符号扩展,由于被除数字长必须是除数两倍,所以需要符号扩展

指令:

​ cbw:al->ax

​ cwd:ax->dx,ax

扩展方式:

​ 无符号数:高位置零

​ 有符号数:高位是低位符号的扩展

其实也就是低位的最高位是0就补0,不然就补1

注意:

​ 不影响标志位

定义数据指令

数据标号 db、dw(单字,注意dword是双字)、dd(双字)、dq(四字)、dt(十个字节) 操作数1 操作数2….这里可以用dup具体用法上边写过了,另外直接对标号使用用的是地址

操作数可以是常数、或者表达式

属性修改运算符

说明:类型可以是BYTE、WORD、DWORD、NEAR、 FAR…

示例: DATA1 DB 26H DATA2 DW 5030H MOV AX, WORD PTR DATA1 ADD BYTE PTR DATA2, BL

上例中的: MOV AX,WORD PTR OPER1+1 MOV AL, BYTE PTR OPER2

表达式赋值伪操作

  1. 等值语句EQU

用来给表达式赋予一个名字

例:

⑴ PORT EQU 1234

⑵ BUFF EQU PORT+58

⑶ MEM EQU DS:[BP+20H]

⑷ COUNT EQU CX

⑸ ABC EQU AAA

  1. 等号语句

    NUM=34

    NUM=34+1

EQU不能重复定义,=可以

ORG

如下,也就是将aa的数据存放在了偏移地址为20的内存中。

org 20

aa dw 2

org 40

bb db,?

属性返回置运算符

seg

格式: SEG 变量/标号 n

功能:返回变量或标号的段基址 n

示例: MOV AX, SEG X1 MOV BX, SEG ARRAY 如果变量X1所在段的段基址为0915H,变量 ARRAY所在段的段基址为0947H,那么上面两条 指令汇编后就分别为: MOV AX, 0915H MOV BX, 0947H

offset

同上,返回偏移地址

type

返回变量或标号的类型属性值

如果该表达式是变量,则返回该变量的 以字节数表示的类型,DB为1,DW为 2 ,DD为4,DF为8….

如果表达式是标号,则返回代表该标号 的数值类型,NEAR是-1,FAR为-2。

如果表达式是常数,则应该回送0

length

如果只有一个dup,则返回dup的个数,否则返回1?还是返回第一个?

格式:length 变量

该指令仅加在变量前,对于变量中使用DUP 的情况,返回分配的单元数(例如 3 dup(?))则返回3,否则仅返回其中一项数据的情况

size

字节总数:type*length

地址计数器

$

指令中表示该指令的首字节地址

数据中表示即将分配出去的地址值

逻辑运算指令

逻辑非指令:NOT OPR * OPR不能为立即数

执行操作: (OPR) ¬ ¬ (OPR) * 不影响标志位

逻辑与指令:AND DST, SRC

执行操作: (DST) ¬ (DST) Ù (SRC)

逻辑或指令:OR DST, SRC

执行操作: (DST) ¬ (DST) Ú (SRC)

异或指令: XOR DST, SRC

执行操作: (DST) ¬ (DST) “ (SRC)

测试指令: TEST OPR1, OPR2 (只改变标志寄存器的AND)

执行操作: (OPR1) Ù (OPR2)

移位指令

格式:例如SHL OPR, CNT(一个是操作数,一个是移位次数(二进制))

逻辑左移:SHL(最高位移入cf,低位补0)

逻辑右移:SHR(相反)

算数左移:SAL(同逻辑左移)

算数右移:SAR(最低为移入cf,最高位不变)


循环移位指令

ROL,ROR(不带进位,类似于不带头节点的循环链表)

RCL,RCR(带进位,类似于带头节点的循环链表)

dos调用

单字符输入

MOV AH,1H

INT 21H

送入的字符存放在AL

单字符输出

MOV DL,’A’

MOV AH,2H

INT 21H

事先把字符送入DL

大小写转换

大写字母二进制和小写字母的二进制不同在于,小写左数第三位是1,大写是0,所以可以通过AND,OR来转换,也可以通过加减20H。

字符串输入

调用10号功能

首先定义缓冲区

BUFFER DB 10,?,10 DUP(?)

其中10代表最大字符数,?处系统会自动填入实际输入的字符数。若输入字符超过缓冲区能容纳的 个数,则系统忽略此字符并响铃警告。

MOV AX,SEG BUFFER
MOV DS,AX
MOV DX,OFFSET BUFFER
MOV AH,10
INT 21H

显示字符串

调用9号功能,要以$结尾

DISPLAY DB ‘Very Good!’ , ‘$’
……
MOV AX,SEG DISPLAY
MOV DS,AX
LEA DX,DISPLAY
MOV AH,9
INT 21H

十进制加减运算

在计算机中采用BCD码来表示十进制数。BCD码就是使用四位二进制数表示一位十进制数。在8086/8088系统中,将BCD码分为两种格式:

  1. 压缩型(组合型、装配型、PACKED)

    一个字节表示两个BCD码,即两位十进制数,例如:0010 0011 表示十进制数的23

  2. 非压缩型(非组合型、拆散型、UNPACKED)。

    一个字节的低四位表示一个BCD码, 而高四位对所表示的十进制数没有影响。 所以对于非压缩形,09h和’9‘代表的是一样的,因为高位的3忽略了。常为0000B或0011B。例如:0000 1001与0011 1001都是十进制数9的非组合型的BCD码。

压缩BCD的加法调整

压缩的BCD码加法调整

格式:DAA

功能:

​ 如果AL的低4位大于9,则将AL加6,并将辅助进位标志AF置1 (因为相当于16进制,9就相当于15,也就是把16进制的数转化为10进制)

​ 如果AL的高4位大于9,将AL加60H,并将进位标志CF置1(同上,调整的是十位所以加了60h,上一个是06h)

注意

​ 在执行DAA指令前,必须是用ADD或ADC完成了加 法操作,且加的结果放在AL中

X DB 05H
Y DB 07H
……
MOV AL,X
ADD AL,Y ;相加后,(AL)=00001100=0CH
DAA ;加6调整后,(AL)=00010010=12H(压缩的BCD码)

压缩BCD的减法调整

压缩的BCD码减法调整

格式:DAS

功能:

​ 如果AL的低4位大于9,则将AL减6,并将辅助进位标志AF置1 (因为相当于16进制,9就相当于15,也就是把16进制的数转化为10进制)

​ 如果AL的高4位大于9,将AL减60H,并将进位标志CF置1(同上,调整的是十位所以加了60h,上一个是06h)

十进制计算62-38=24
W1 DB 62H ;BCD码表示的十进制62
W2 DB 38H
……
MOV AL,W1
SUB AL,W2 ;相减后,(AL)=2AH
DAS ;减6调整后,(AL)=24H

非压缩BCD的加法调整

非压缩的BCD码加法调整

格式:AAA

功能:

​ 如果AL的低4位大于9或者af=1(辅助进位标识),将AL加6、AH加1,AL的 高4位清零、CF、AF置1 由于非压缩的BCD码用1个字节表示1个十进制数, 所以调整后若加上30H就是该数值的ASCII码。因为0的ascii码是30h

注意

​ 在AAA指令执行前,必须是使用ADD或ADC指令完成了 加法,且结果是在AL中。AAA指令对AL中内容进行校正

例 十进制计算6+8=14,用非压缩的BCD码表示并显示在屏幕上。
T1 DB 06H
T2 DB 08H
……
MOV AL,T1 ;(AL)=00000110=06H
ADD AL,T2 ;(AL)=00001110=0EH
AAA ;调整后(AH)=01H,(AL)=04H
ADD AX,3030H ;AH、AL分别加上30H,变成ASCII码
MOV BX,AX ;用BX保存
MOV DL,BH ;显示“1”
MOV AH,2 ;2号显示功能
INT 21H ;DOS中断调用
MOV DL,BL ;显示“4”
INT 21H

非压缩BCD的减法调整

非压缩的BCD码减法调整

格式:AAS

功能:

​ 如果AL的低4位大于9,将AL减6、AH减1, AL的高4位清零、CF、AF置1

例 十进制计算57-18=39,用非压缩的BCD码表示。
MOV AX,0507H
MOV BX,0108H
SUB AL,BL
SUB AH,BH ;高位不用带借位减
AAS ;减法调整后(AX)=0309H

非压缩BCD的乘法调整

格式:AAM (ASCII Adjust Multiply)

功能: 将乘积AX中的2个非压缩的BCD码调整。 AL除以0AH,得到的商送AH,余数送入 AL。即乘积的高位数在AH 、低位数在 AL中

例 十进制乘法6×8=48,用非压缩的BCD码表示,并显示。
P1 DB 06H
P2 DB 08H
……
MOV AL,P1 ;(AL)=00000110=06H
IMUL P2 ;(AL)=00110000=30H
AAM ;调整后(AH)=04H,(AL)=08H
ADD AX,3030H ;AH、AL分别加上30H
MOV BX,AX ;用BX保存
MOV DL,BH ;显示“4”
MOV AH,2
INT 21H
MOV DL,BL ;显示“8”
INT 21H

非压缩BCD的除法调整

格式:AAD (ASCII Adjust Division)

功能:在做除法之前,将被除数AX中的2 个非压缩的BCD码调整。 (AL)=(AL)+(AH)*10,AH清零。除法之 后,商在AL 、余数在AH中.

考试复习

标号

对于数据标号,即a db 1,2,3,则在代码段中的a就会被替换成data:[0],前提是要在assume里面关联ds与data。被替换以后,你就懂了吧,它可以表示一个数据,也可以用来寻址a[si]也就是cs:0[si]

offset

offset只能和数据标号搭配,而不能用复杂的例如ds:[bx]等。。offset取出的地址可以用来mov、add之类的。。

寻址

push word ptr 20[bx+si-2]这里是可以写表达式的

栈顶应该是sp-1吗

异或

XOR CX,CX

相当于mov cx,0,但是异或效率更高

标号

关于标号的一些问题

X1 DB 12H, 34H, 56H
X2 DW 78H, 90H
ADR1 DW X1
ADR2 DW X2

如上,ADR1和ADR2表示的是X1和X2的地址,即偏移地址,0000和0300。