汇编语言知识总结

----------------------汇编语言------------------------
1 byte = 8 bit 1个字节=8位二进制
1 KB = 1024 byte = 2的10次方byte
1 MB = 1024 KB = 2的20次方byte
1GB = 1024 MB = 2的30次方byte

CPU中一定有可以存放地址信息和数据信息的地方——寄存器

我们汇编程序员就是通过汇编语言中的汇编指令去修改寄存器中的内容从而控制CPU,就可以控制整个计算机了

寄存器是相互独立的

DS ES SS CS 都是冒号左边的一种地址信息
mov指令 将逗号右边的给逗号左边的

AX BX CX DX
通用寄存器,存放数据的,数据寄存器(16位寄存器)
1byte = 8bit
2byte = 16bit 0000 0000 0000 0000 ~ 1111 1111 1111 1111 0~FFFH 0~65535 65536

u指令 将某个内存地址开始的字节全部当作指令
d指令 将某个内存地址开始的字节全部当作数据
ip寄存器的数值和指令有关
-r ds
DS 073F
: 0
改变DS寄存器的值

指令和数据在内存中没有区别
8086机中,任意时刻,CPU将CS:IP指向的内容当作指令执行。

汇编指令 jmp 转移指令,可以修改 CS 和 IP 这2个寄存器,决定了CPU从哪里读取指令
jmp 2000:0
jmp 寄存器 => mov ip,ax

debug 调试工具
-r 可以查看和改变CPU寄存器中的内容
-d 可以查看内存中的内容
-u 可以将内存中的机器指令翻译成汇编
-a 可以以汇编指令的格式在内存中写入一条汇编指令
-t 执行当前 CS:IP 所指向的机器指令,可以执行一条或多条指令
-e 可以改写内存中的内容
-q 退出debug,返回command中,因为debug是由command加载运行的

物理地址=段地址*10h+偏移地址

段地址寄存器:ds es ss cs
偏移地址寄存器:sp bp si di ip bx
ds:bx---------数据段地址寄存器
cs:ip----------代码段
ss:sp---------栈段
dx-----------累加寄存器,暂时存放cx中的值
cx-------循环计数寄存器
dx:ax----------存放16位乘法结果,dx存放高位,ax存放低位;如果是除法,ax存放商,dx存放余数。
bx、si、di、bp只有这4个寄存器可以用在“[…]"中来进行内存单元的寻址。在“[…]"中这4个寄存器可以单独出现,或只能以4种组合出现:bx和si、bx和di、bp和si、bp和di。
只要在“[…]"中使用寄存器bp,而指令没有显性地给出段地址,段地址就默认在ss中。

偏移地址16位,变化范围为0~FFFFH,仅用偏移地址来寻址最多可寻64KB个内存单元
一个段的起始地址一定是16的倍数
8086CPU不支持将数据直接送入段寄存器的操作。
段空间0:200~0:2FF是相对安全的(256个字节)
ds = cs - 10h
8086CPU的入栈和出栈都是以字为单位进行的。
任意时刻,ss:sp指向栈顶元素。push指令和pop指令执行时,CPU从ss和sp中得到栈顶的地址。用栈来暂存以后需要恢复的寄存器中的内容,出栈的顺序要入栈的顺序相反。
一个栈段的容量最大为64KB
在汇编源程序中,数据不能以字母开头,所以在前面要加0。
在DOS中运行程序时,是command将程序加载入内存,所以程序运行结束返回到command中,而在这里是Debug将程序加载入内存,所以程序运行结束后返回debug中。
如果段中的数据占N个字节,则程序加载后,该段实际占有的空间为「N/16」*16。

伪指令:
assume cs:codesg
codesg segment
代码段
codesg ends
end
用debug来执行程序

dw----定义字型数据,所占内存空间16个字节
db是一种字节单位,如db是定义字节型的数据,dw定义字类型数据,dd定义双字类型的数据。问号表示一个空的单元
dup是一个操作符,和db、dw、dd等数据定义伪指令配合使用,用来进行数据的重复。
db 重复的次数 dup(重复的字节型数据)
dw 重复的次数 dup(重复的字型数据)
dd 重复的次数 dup(重复的双字型数据)

assume cs:code
code segment

数据(数据存放在cs:0000中)

start:

代码

code ends
end start

将数据、代码、栈放入不同的段
段名就相当于一个标号,代表了段地址,被编译器处理为一个代表段地址的数值

and 指令:逻辑与指令,按位进行与运算
例:and byte ptr [si],11011111b (将ds:si所指单元中的字母转化为大写)
操作数可以是 8 位、16 位、32 位和 64 位,但是两个操作数必须是同样大小。

or 指令:逻辑或指令,按位进行或运算
例:or al,00100000B ;将al中的ASCII码的第5位置为1,变为小写字母
操作数可以是 8 位、16 位、32 位和 64 位,但是两个操作数必须是同样大小。

一个字母,不管它原来是大写还是小写,当它的第5位置0,它就必将变为大写字母;将它的第5位置1,它就必将变为小写字母。

立即数(idea)
在没有寄存器名存在的情况下,用操作符 X ptr 指明内存单元的长度,X可以是word或byte

div除法指令
除数:在一个寄存器或内存单元中
被除数:默认放在ax或dx和ax中
div word ptr [bx+si+8]
含义:(ax) = [(dx)*10000H + (ax)] / ((ds)*16+(bx)+(si)+8) 的商
(ax) = [(dx)*10000H + (ax)] / ((ds)*16+(bx)+(si)+8) 的余数

可以修改IP,或同时修改CS和IP的指令统称为转移指令。
段内转移:jmp ax
段间转移:jmp 1000:0
分类:
无条件转移指令(jmp)
条件转移指令
循环指令(loop)
过程
中断

操作符offset------取得标号的偏移地址
操作符seg---------取得标号的段地址

CPU在执行jmp指令的时候并不需要转移的目的地址。
段内短转移:
jmp short 标号(转到标号处执行指令)
功能(IP)=(IP)+8位位移
8位位移=标号处的地址-jmp指令后的第一个字节的地址
对IP的修改范围为:-128~127

段内近转移:
jmp near ptr 标号
功能 :(IP)=(IP)+16位位移
16位位移=标号处的地址-jmp指令后的第一个字节的地址
对IP修改范围为-32768~32767

转移的目的地址在指令中的jmp指令
段间转移(远转移)
jmp far ptr 标号
功能:指明了指令用标号的段地址和偏移地址修改CS和IP
(CS)=标号所在的段的段地址;(IP)=标号在段中的偏移地址

转移地址在寄存器中的jmp指令
jmp 16位reg------mov IP,16位reg
功能:(IP)=(16位reg)

转移地址在内存中的jmp指令
段内转移
jmp word ptr 内存单元地址
功能:从内存单元地址处开始存放着一个字,是转移的目的偏移地址。

段间转移
jmp dword ptr 内存单元地址
功能:从内存单元地址处开始存放着两个字,高地址处的字是转移的目的段地址,低地址处是转移的目的偏移地址。

jcxz 标号
功能:如果cx==0,转移到标号处执行。当cx不等于0时,什么也不做(程序向下执行)

loop 标号
功能:dec cx
if((cx)≠0) jmp short 标号;
loop指令默认cx为循环计数器。
一般来说,暂存数据的时候,我们都应该用栈。

call和ret指令都是转移指令,修改IP或者同时修改CS和IP。call和ret指令通常配合使用。

ret指令用栈中的数据,修改IP的内容,从而实现近转移。pop ip
retf指令用栈中的数据,修改CS和IP的内容,从而实现远转移。pop ip pop cs

依据位移进行转移的call指令
call 标号(将当前的ip压栈后,转到标号处执行指令)
push ip
jmp near ptr 标号

转移的目的地址在指令中的call指令
call far ptr 标号(段间转移)

push cs
push ip
jmp far ptr 标号

转移地址在寄存器中的call指令
call 16位reg

push ip
jmp 16位reg(mov ip,16位reg)

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

push ip
jmp word ptr 内存单元地址
功能:从内存单元地址处开始存放着一个字,是转移的目的偏移地址。

call dword ptr 内存单元地址
push cs
push ip
jmp dword ptr 内存单元地址
功能:从内存单元地址处开始存放着两个字,高地址处的字是转移的目的段地址,低地址处是转移的目的偏移地址。

mull乘法指令
两个相乘的数:要么都是8位,要么都是16位。如果是8位,一个默认放在AL中,另一个放在8位reg或内存字节单元中;如果是16位,一个默认在AX中,另一个放在16位reg或内存单元中。
结果:如果是8位乘法,结果默认放在AX中;如果是16位乘法,结果高位默认放在DX中,低位放在AX中放。
格式:
mul reg
mul 内存单元

标志寄存器flag
零标志ZF(Zero Flag)
零标志ZF用来反映运算结果是否为0。如果运算结果为0,则其值为1,否则其值为0。在判断运算结果是否为0时,可使用此标志位。
奇偶标志PF(Parity Flag)
奇偶标志PF用于反映运算结果中“1”的个数的奇偶性。如果“1”的个数为偶数,则PF的值为1,如果为奇数,则其值为0。
利用PF可进行奇偶校验检查,或产生奇偶校验位。在数据传送过程中,为了提供传送的可靠性,如果采用奇偶校验的方法,就可使用该标志位。
符号标志SF(Sign Flag)
符号标志SF用来反映运算结果的符号位,它与运算结果的最高位相同。运算结果为负时,SF的值为1;如果非负,其值为0。当我们将数据当作有符号数来运算的时候,可以通过它来得知结果的正负。如果我们将数据当作无符号数来运算,SF的值则没有意义。
进位标志CF(Carry Flag)
进位标志CF主要用来反映运算是否产生进位或借位。如果运算结果的最高位产生了一个进位或借位,那么,其值为1,否则其值为0。
inc 和 loop 指令不影响CF位。
使用该标志位的情况有:多字(字节)数的加减运算,无符号数的大小比较运算,移位操作,字(字节)之间移位,专门改变CF值的指令等。
溢出标志OF(Overflow Flag)
溢出标志OF用于反映有符号数加减运算所得结果是否溢出。如果运算结果超过当前运算位数所能表示的范围,则称为溢出,OF的值被置为1,否则,OF的值被清为0。
方向标志DF(Direction Flag)
在串处理指令中,控制每次操作后si、di的增减。df=0 每次操作后si、di递增。df=1 每次操作后si、di递减。
追踪标志TF(Trap Flag)
当追踪标志TF被置为1时,CPU进入单步执行方式,即每执行一条指令,产生一个单步中断请求。这种方式主要用于程序的调试。指令系统中没有专门的指令来改变标志位TF的值,但程序员可用其它办法来改变其值。
取得中断类型码1
标志寄存器入栈,TF、IF设置为0
CS、IP入栈
(IP)=(14),(CS)=(14+2)
add、sub、mul、div、inc、or、and、cmp、int、adc、iret、popf等,它们大都是运算指令(进行逻辑或算术运算),影响标志寄存器;mov、push、pop、jmp等,它们大都是传送指令,对标志寄存器没有影响。

adc带进位加法指令
指令格式:adc操作对象1,操作对象2
功能:操作对象1 = 操作对象1 + 操作对象2 + CF

sbb带借位减法指令
指令格式:sbb操作对象1,操作对象2
功能:操作对象1 = 操作对象1 - 操作对象2 - CF

cmp比较指令
指令格式:cmp 操作对象1,操作对象2
功能:计算操作对象1 - 操作对象2 但并不保存结果,仅仅根据计算结果对标志寄存器进行设置。
如果(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;

指令cmp ax,bx的逻辑含义是比较ax和bx中的值,如果执行后:
zf=1,说明(ax)=(bx)
zf=0,说明(ax)≠(bx)
cf=1,说明(ax)<(bx)
cf=0,说明(ax)≥(bx)
cf=0并且zf=0,说明(ax)>(bx)
cf=1或zf=1,说明(ax)≤(bx)

1)如果sf=1,而of=0
of=0, 说明没有溢出,逻辑上真正结果的正负=实际结果的正负;
因sf=1, 实际结果为负,所以逻辑上真正的结果为负,所以(ah)<(bh)。
2)如果sf=1,而of=1
of=1, 说明有溢出,逻辑上真正结果的正负≠实际结果的正负;
因sf=1, 实际结果为负。
实际结果为负,而又有溢出,这说明了是由于溢出导致了实际结果为负,简单分析一下,就可以看出,如果因为溢出导致了实际结果为负,那么逻辑上真正的结果必然为正。
这样,sf=1,of=1,说明了(ah)>(bh)。
3)如果sf=0, 而of=1
of=1, 说明有溢出,逻辑上真正结果的正负≠实际结果的正负;
因sf=0,实际结果非负。而of=1说明有溢出,则结果非0,所以实际结果为正。
实际结果为正,而又有溢出,这说明是由于溢出导致了实际结果非负,简单分析一下,就可以看出,如果因为溢出导致了实际结果为正,那么逻辑上真正的结果必然为负。
这样:sf=0, of=1,说明了(ah)<(bh)。
4)如果sf=0,而of=0
of=0, 说明没有溢出,逻辑上真正结果的正负=实际结果的正负;
因sf=0,实际结果非负,所以逻辑上真正的结果非负,所以(ah)≥(bh)。

常用的根据无符号数的比较结果进行转移的条件转移指令
指令 含义 检测的相关标志位
je 等于则转移 zf=1
jne 不等于则转移 zf=0
jb 低于则转移 cf=1
jnb 不低于则转移 cf=0
ja 高于则转移 cf=0且zf=0
jna 不高于则转移 cf=1或zf=1

串传送指令
movsb
功能:执行movsb指令相当于进行下面几步操作。
mov es:[di],byte ptr ds:[si] ;8086并不支持这样的指令,这里只是个描述
如果df=0 如果df=1
inc si dec si
inc di dec di

movsw
mov es:[di],word ptr ds:[si] ;8086并不支持这样的指令,这里只是个描述
如果df=0 如果df=1
add si,2 sub si,2
add di,2 sub di,2

cld指令:将标志寄存器的df位置0
std指令:将标志寄存器的df位置1

一般来说,movsb和movsw都和rep配合使用,格式如下:
rep movsb rep movsw
功能:s:movsb s:movsb
loop s loop s
rep movsb 可以循环实现(cx)个字符的传送

pushf的功能是将标志寄存器的值压栈,popf是从栈中弹出数据,送入标志寄存器中。

标志 值为1 值为0
OF OV NV
SF NG PL
ZF ZR NZ
PF PE PO
CF CY NC
DF DN UP

中断类型码
除法错误 0
单步执行 1
执行into指令 4
执行int指令,int n ,指令中n为字节型立即数,是提供给CPU的中断类型码。可以使用int指令调用任何一个中断的中断处理程序。

int指令
格式为:int n,n为中断类型码,它的功能是引发中断过程
中断过程
取得中断类型码N
pushf
TF=0,IF=0
push CS
push IP
(IP)=(N4),(CS)=(N4+2)

iret 指令
pop IP
pop CS
popf

int指令和iret指令的配合使用与call指令和ret指令的配合使用具有相似的思路。

inc指令 加1指令
inc dl 相当于 add dl,1
inc指令的操作数的类型可以是通用寄存器或存储单元,但不可以是段寄存器。字或字节操作均可。对于存储单元,需要用byte ptr或者word ptr说明是字节还是字操作。

dec指令 减1指令
dec dl 相当于 sub dl,1

shl指令
逻辑左移指令
将一个寄存器或内存单元中的数据向左移动;
将最后移出的一位写入CF中;
最低位用0补充。
如果移动位数大于1时,必须将移动位数放在cl中。

shr指令
逻辑右移指令
将一个寄存器或内存单元中的数据向右移动;
将最后移出的一位写入CF中;
最高位用0补充。
如果移动位数大于1时,必须将移动位数放在cl中。

sti指令,设置IF=1
cli指令,设置IF=0

ret n指令
pop ip
add sp,n

BIOS提供了int 9中断例程,用来进行基本的键盘输入处理。


版权声明:本文为weixin_45795497原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。