汇编指令学习

INT OUT

期末的计算机组成原理的课程设计,要学习看懂汇编语言,记录一些汇编指令
CPU对外设的操作通过专门的端口读写指令来完成;
  读端口用IN指令,写端口用OUT指令。

IN AL,21H;表示从21H端口读取一字节数据到AL
IN AX,21H;表示从端口地址21H读取1字节数据到AL,从端口地址22H读取1字节到AH

MOV DX,379H
  IN AL,DX ;从端口379H读取1字节到AL
OUT 21H,AL;将AL的值写入21H端口
  OUT 21H,AX;将AX的值写入端口地址21H开始的连续两个字节。

assume cs:code,ds:data

assume,这个单词是“假设”的意思,告诉编译器,段寄存器和段名之间的关系
这是段分配语句,是条伪指令,一般放在代码段的第一条位置,段分配语句仅仅是建立段寄存器和段名之间关系,不具有赋值功能,
比如你创建了几个段,怎么知道它是代码段,它是数据段,就靠这条语句,
因为段名是可以随意取的,你可以把code取成代码段,也可以是其他名字,通过这条语句就可以把他们的关系建立起来

mov dx,offset s

这句话意思是将s的偏移地址传给dx

data segment

叫完整段定义
可以随意设置段属性,随意使用各种段
但在不熟悉该环境下段的定义约定,建议使用简化段定义,否则造成一系列兼容问题
汇编的基本框架

CODE SEGMENT 
START: 
........ //定义代码段 当然就是要执行的程序代码了 
CODE ENDS 
END START

int 21h

是DOS的中断调用
比如

MOV AH 4CH
INT 21H

是返回DOS系统的
通过给AH寄存器赋值4CH,然后调用INT 21H指令,计算机就会根据AH寄存器中的值执行相应的操作,
其中4CH是返回DOS系统,还可给AH寄存器赋其他值,所对于的操作这里也有

lea指令

就是目标地址传送指令: 将一个近地址指针写入到指定的寄存器。格式:
LEA reg16,mem16
其中reg16必须是一个16位通用寄存器,mem16必须是一个存储器,执行这个指令后,就将mem16所指的16位偏移地址传送reg16中。
比如: LEA AX,BUF
就是将存储器中BUF所指的地址传送给AX.
区别MOV传送指令:
MOV传送的是地址所指的内容,而LEA只是地址。
当源操作数很简单的情况下,完全可以用mov指令代替lea指令,
如lea esi,Buffer,完全可以用指令mov esi,offset Buffer代替;
但当源操作数稍微复杂一点的话,单用mov指令就代替不了了,至少要用到算术运算指令。
指令集中提供lea指令,就是为了减少这些计算上的麻烦。

cmp

可以认为是compare(比较)的意思。在进行比较的时候将个数做减法运算,这个运算是影响符号位的,(大数减小数,符号位为+,反则为-)
所以执行该指令后你可以通过查询符号位CF是0还是1就可以知道两个数那个大了。

jnc

可用于两个数的判断!jnc是进位位为0则转移!而两个数的比较就是想减,
例如X-Y,X小于Y,X就要借位,这样进位位就为1,如果X大于Y,X就不需要借位,这样进位位为0
jnc是一条跳转指令,当进位标记C为0时跳转,为1时执行后面的指令。

OF与CF的区别

of的设置,以加法为例,如果两数符号相同,结果却相反,则of=1;否则of=0;(如果两数符号相反,是不会溢出的)。
cf的设置,最高有效位(bit7,比如)向高位进位则为1,否则为0。所以实际上of是表示有符号数的溢出,cf是表示无符号数的溢出。

jz

JZ(Jump if Zero)是此前的运算结果为0时跳转。
若此前运算结果不为0,则不跳转,执行JZ指令后面的下一条指令。
判断结果是否为零,靠的是ZF标志位状态。
若结果是0,则ZF=1
若结果不是0,则ZF=0
所以,JZ指令是在ZF=1时跳转,ZF=0时不跳转。

jz与jnz的区别

jnz结果不为零(或不相等)则转移。

jz即零标志为1就跳转。

test

测试(两操作数作与运算,仅修改标志位,不回送结果).
TEST AX,BX 与 AND AX,BX 命令有相同效果
ret指令和retf指令
ret指令用栈中的数据,修改IP的内容,从而实现近转移
retf指令用栈的数据,修改CS和IP的内容,从而实现远转移

CPU执行ret指令时,相当于进行:

pop IP

CPU执行retf指令时,相当于进行:

pop IP
pop CS

call

CALL(LCALL)指令执行时,进行两步操作:
(1)将程序当前执行的位置IP压入堆栈中;   (2)转移到调用的子程序。
JMP和CALL的一个朴实的区别就是:
JMP跳走之后,它可以跳回来,也可以再跳到别的地方不回去。
CALL调用子程序后,就算再调用别的子程序也一定会返回主程序。
JMP和CALL在有些时候应该都可以用吧→ _→

pop

pop ax ,就是将栈顶的那个数取出并存入到ax寄存器中
push ax 是把ax里的值压入堆栈

rol

ROL和ROR指令
循环左移/右移指令只是移位方向不同,它们移出的位不仅要进入CF,而且还要填补空出的位。

例如:

MOV AL,82H

ROL AL,1

首先把82H转换成二进制数10000010B
循环左移1位后变成:00000101B,换算成十六进制数便是05H
循环右移1位后变成:01000001B,换算成十六进制数便是41H

DEC

DEC是减1指令,该指令使操作数的内容减1,然后再送回该操作数。该操作数可以是寄存器操作数、存储器操作数。
例如:
DEC AL;AL内容减1,然后再送AL
DEC AX;AX减内容1,然后再送AX
DEC CONT;CONT减内容1,然后再送CONT

proc

是子程序定义伪指令, far是该子程序的属性,决定调用程序和子程序是否在同一代码段
如下:为子程序定义及说明,

子程序名 PROC NEAR ( 或 FAR )
……
ret
子程序名 ENDP
子程序名为符合语法的标识符

NEAR属性(段内近调用): 调用程序和子程序在同一代码段中,只能被相同代码段的其他程序调用;
FAR属性(段间远调用): 调用程序和子程序不在同一代码段中,可以被相同或不同代码段的程序调用.

lea

LEA指令的功能是取偏移地址,例如LEA AX,[1000H],作用是将源操作数[1000H]的偏移地址1000H送至AX;
MOV指令的功能是传送数据,例如MOV AX,[1000H],作用是将1000H作为偏移地址,寻址找到内存单元,将该内存单元中的数据送至AX;
LEA指令的功能是取偏移地址,例如LEA AX,[1000H],作用是将源操作数[1000H]的偏移地址1000H送至AX。理解时,可直接将[ ]去掉,等同于MOV AX,1000H。
再如:LEA BX,[AX],等同于MOV BX,AX;LEA BX,TABLE 等同于 MOV BX,OFFSET TABLE。
但有时不能直接使用MOV代替:
比如:

LEA AX,[SI+6] 不能直接替换成:MOV AX,SI+6;但可替换为:
MOV AX,SI
ADD AX,6
两步完成。

xlat

是一种指令程序。操作是以DS:[BX+AL]为地址,提取存储器中的一个字节再送入AL。
例一

X DW 1122H,3344H,5566H,7788H。
LEA BX,X。
MOV AL,03H。
XLAT。

结果AL为33H。
XLAT作用:将((BX)+(AL))送给(AL)—-简单:将BX为首地址的,偏移地址为AL的内容送给AL。
在运行XLAT之前,AL=3 BX=(X的首地址)。
这时BX+AL就是33….为什么?注意高地址放在下面。
也就是。
22——BX指向这里。
11。
44。
33—–偏移地址AL为3的位置就是这里。
XLAT X。
在执行XLAT之前,先将X的地址送给BX,偏移次数送给AL。
XLAT即为查找指令 (一个字节)。

shl和shr指令

shl和shr是逻辑移位指令。

shl是逻辑左移指令,它的功能为:

(1)将一个寄存器或内存单元中的数据向左移位;

(2)将最后移出的一位写入CF中;

(3)最低位用0补充。

指令:
mov al,01001000b

shl al,1 ;将al中数据左移一位

执行后(al)=10010000b,CF=0。

注意:

如果移动位数大于1时,必须将移动位数放在cl中。

比如,指令:

mov al,01010001b

mov cl,3

shl al,cl

执行后(al)=10001000b,因为最后移出的一位是0,所以CF=0。

shr是逻辑右移指令,它和shl所进行的操作刚好相反。

SP,BP ,SI,DI作用

sp:表示栈顶指针,指向栈顶地址.与SS相配合使用.ss为栈段.

bp:是基址指针,段地址默认在SS中.可以定位物理地址,比如:”mov ax,[bp+si+6]/mov ax,[bp+di+6].

DI:是目的变址寄存器.一般情况下与ds联用,来确定某个储存单元的地址.

SI:是源变址寄存器,默认段地址和DI一样,在DS中.和DS联用.

这四个寄存器,都是16位的,不可以分割为八位.

要注意,1,sp和bp段地址默认在SS中.2..sp指向栈顶元素地址.有自加和自减能力,而bp没有.但是bp可以定位栈中某个元素的物理地址.

DI和SI

这两个属于变址寄存器.可以和bx.bp联用,但是和bx连用时,段地址在DS中,和bp联用时,段地址在SS中.也可以单独使用,单独使用时,段地址默认在DS中,想要越段使用,加上段前缀即可.

在串指令操作中,si和ds联用,确定目标源地址,di和es(附加段寄存器)联用,确定传送的目的地址.说白了就是,分别寻址数据段和附加段.

在串指令中,si和di具有自加和自减功能,