目录
chapter10:call指令和ret指令
call指令和ret指令都是转移指令,都能够修改IP,或者同时修改IP和CS,这两个指令被用来实现子程序(高级语言中称之为函数)的设计,极其重要。
1.ret和retf
- ret指令用栈中的数据,修改IP的内容,从而实现近转移(段内近转移)
(IP) = ((ss) * 16 + (SP))
(SP) = (SP) + 2
相当于
pop IP
- retf指令用栈中的数据,修改CS和IP的内容,从而实现远转移(段间转移)。
相当于
pop IP
pop CS
2.call指令
- call指令不能实现短转移,call指令实现转移的方法和jmp指令相同。CPU执行call指令时,进行两步操作:
- 将当前的IP或者CS和IP压入栈中
- 转移
1.根据位移进行转移的call指令
- 这种call指令对应的机器指令没有转移的目的地址,而是相对于当前IP的转移地址。
- 指令用法:
call 标号
(将当前的IP(call指令的下一条指令的地址)压入栈后,转到标号处执行指令) - CPU执行此种格式的call指令时,进行如下的操作
1. (sp) = (sp) - 2
;将当前IP存入栈顶,以便函数返回时可以回到call指令的下一条指令执行
2. ((ss) * 16 + (sp)) = (IP)
;转到标号处执行指令
3. (IP) = (IP) + 16位位移
注:16位位移 = 标号处的地址 - call指令后的第一个字节的地址
16位位移的范围为-32768到32767
16位位移由编译程序在编译时算出
- CPU执行
call 标号
时相当于进行
push IP
jmp near ptr 标号
2.转移的目的地址在指令中的call指令
- 指令格式:
call far ptr 标号
。实现的是段间转移 - CPU执行此种格式的call指令时,进行如下的操作
1. (sp) = (sp) - 2
2. ((ss) * 16 + (sp)) = (CS) ;将当前CS存入栈顶
3. (sp) = (sp) - 2
4. ((ss) * 16 + (sp)) = (IP) ;将当前IP存入栈顶
5. (CS) = 标号所在段的段地址
6. (IP) = 标号在段中的偏移地址
- CPU执行
call far ptr 标号
时相当于进行
push cs
push ip
jmp far ptr 标号
3.转移地址在寄存器中的call指令
- 格式:
call 16位寄存器
- 功能:
1. (sp) = (sp) - 2
2. ((ss) * 16 + (sp)) = (IP) ;将当前IP存入栈顶
3. (IP) = (16位寄存器) ;更新IP的值
- CPU执行
call 16位寄存器
时相当于进行
push IP
jmp 16位寄存器
4.转移地址在内存中的call指令
- 转移地址(转移的目的地址的偏移量)在内存中的call指令有两种格式:
1.call word ptr 内存单元地址 (段内转移)
该指令相当于
push IP
jmp word ptr 内存单元地址
2.call dword ptr 内存单元地址(段间转移)
该指令相当于
push CS
push IP
jmp dword ptr 内存单元地址
- 示例:
;下面指令执行后,(IP) =0123H ,(sp) = 0EH
mov sp,10H
mov ax,0123H
mov ds:[0],ax
;偏移地址更改为从ds:[0]开始的两个字节的数据
;将当前的IP压入栈中
call word ptr ds:[0]
;下面指令执行后,(CS) = 0,(IP) = 0123H,(SP) = 0CH
mov sp,10H
mov ax,0123H
mov ds:[0],ax
mov word ptr ds:[2],0
call dword ptr ds:[0]
3.ret指令和call指令配合实现子程序
- 这两条指令配合可以实现类似C语言中的函数调用。使用call指令和ret指令实现子程序的框架如下:
assume cs:code
code segment
;程序入口地址
main:
call sub1;调用子程序sub1
mov ax,4c00h
int 21h
;子程序sub1开始
sub1:
指令
ret;子程序返回
code ends
end main
4.mul指令(乘法指令)
- 规则:
- 两个相乘的数,要么都是8位,要么都是16位。如果是8位,一个默认存放在AL中,另一个放在8位寄存器中或者内存字节单元中。如果是16位,一个默认在AX中,另一个放在16位寄存器中或者内存字单元中。
- 如果是八位乘法,结果默认放在AX中,如果是16位乘法,高位默认在DX,地位在AX
- 格式如下:
mul 寄存器
mul 内存单元
- 示例
;表示(ax) = (al) *((ds) * 16 + 0)
mul byte ptr ds:[0]
chapter11:标志寄存器
CPU中的内部寄存器中,有一种特殊的寄存器,它具有以下三个作用:
- 用来存储相关指令的某些执行结果
- 用来为CPU执行相关指令提供行为依据
- 用来控制CPU的相关工作方式
这些特殊的寄存器在8086CPU中被称为标志寄存器。8086CPU中的标志寄存器有16位,其中存储的信息通常称为程序状态字(PSW)
8086CPU的flag寄存器的结构如下图所示:1、3、5、12、等标志位没有使用,没有含义
1.标志寄存器中的ZF标志位
flag(标志寄存器)的第六位是ZF标志位,他记录相关指令执行后,其结果是否为0.如果结果为0,那么ZF为1,否则ZF为0
;指令执行后,ZF=1
mov ax,1
and ax,0
2.PF标志位
- flag的第二位是PF(Parity Flag)标志位,奇偶标志位。他记录相关指令执行后,其结果的所有bit位中1的个数是否为偶数。如果1的个数为偶数,则PF为1,否则PF为0
;执行后结果有三个1,所以PF=0
mov al,1
add al,10
3.SF标志位
flag的第七位是SF,符号标志位。它记录相关指令执行后,其结果是否为负。如果结果为负,则sf等于1.否则sf为0
;指令执行后,结果为10000010B,sf = 1
;如果指令进行的是有符号运算,那么结果为负(因为sf为1)
mov al,10000001B
add al,1
注意:传送指令push,pop,mov等不影响标志寄存器的状态。
4.CF标志位
flag的第0位是CF,进位标志位。一般情况下,在进行无符号运算 的时候,它记录了运算结果的最高有效位向更高位的进位值,或者从更高位的借位值。
mov al,98H
;执行后,(AL) = 30H,CF = 1
;CF记录了最高有效位向更高位的进位值
add al,al
mov al,97H
;执行后(al) = FFH,CF = 1
;CF记录了向更高位的借位值
sub al,98H
5.of标志位
- 溢出:运算结果超出了机器所能表示的范围
- 在进行有符号数运算时 ,可能发生溢出而造成结果的错误。则CPU需要对指令执行后是否产生溢出进行记录。flag的第11位是OF这个溢出标志位,如果发生溢出,则OF等于1,否则OF等于0.
注意CF与OF的区别:CF是对无符号数运算有意义的标志位,而OF是对有符号数运算有意义的标志位
6.adc指令
- abc是带进位加法指令,它利用了CF位上记录的进位值。
- 指令格式:adc 操作对象1,操作对象2
- 功能:操作对象1 = 操作对象1 + 操作对象2 + CF
提供adc指令的缘有:和add指令配合就可以对更大的数据进行加法运算
;低位相加
add al,bl
;高位相加再加上低位相加产生的进位值
adc ah,bh
- 举例:
;计算1EF000H + 201000H
mov ax,001EH
mov bx,0F000H
add bx,1000H
adc ax,0020H
7.sbb指令
- sbb是借位减法指令,它利用了CF位上记录的借位值。
- 指令格式:sbb 操作对象1,操作对象2
- 功能:操作对象1 = 操作对象1 -操作对象2 - CF
- 举例
;计算003E1000H - 00202000H
mov bx,1000H
mov ax,003EH
sub bx,2000H
sbb ax,0020H
8.cmp指令
- cmp指令是比较指令,cmp指令的功能相当于减法指令,只是不保存结果。cmp指令执行后,将根据计算结果对标志寄存器进行设置。
- cmp指令格式:cmp 操作对象1,操作对象2
- 功能:计算操作对象1 - 操作对象2
在考察SF标志位(得知实际结果的正负)的同时,考察OF标志位(得知有无溢出),就可以得知逻辑上真正结果的正负,同时知道比较的结果。
9.根据比较结果的条件转移指令
根据某种条件,决定是否修改IP。
- jcxz就是一个条件指令,它监测cx的值,如果(cx) = 0,则修改IP。
- 根据cmp指令的比较结果进行转移的指令:
- 根据无符号数的比较结果进行转移的条件转移指令:通过检测ZF、CF的值。常用的条件指令如下所示,其中b表示below、a表示above、j表示jump。使用这些条件指令和cmp指令结合可以实现高级编程语言中的选择结构,比如说if...else
- 根据有符号数的比较结果进行转移的条件转移指令:通过检测sf、of、zf的值
- 根据无符号数的比较结果进行转移的条件转移指令:通过检测ZF、CF的值。常用的条件指令如下所示,其中b表示below、a表示above、j表示jump。使用这些条件指令和cmp指令结合可以实现高级编程语言中的选择结构,比如说if...else
10.DF标志和串传送指令
- flag的第十位是DF标志位(方向标志位)。在串处理指令中,控制si和di的增减。
df = 0,每次操作后,si和di递增
df = 1,每次操作后,si和di递减
- 串传送指令1:movsb(传送一个字节),功能主要是将ds:si指向的内存单元的字节送入es:di中,然后根据标志寄存器df位的值,将si和di递增1或者递减1
执行movsb指令相当于执行下列操作
((es) * 16 + (di)) = ((ds) * 16 + (si))
如果df=0,将si,di递增
如果df=1,将si,di递减
- 串传送指令2:movsw(传送一个字),功能主要是将ds:si指向的内存单元的字送入es:di中,然后根据标志寄存器df位的值,将si和di递增2或者递减2
用汇编语法描述movsw的功能如下:
mov es:[di],word ptr ds:[si] ;只是描述,实际并不存在这样的指令
- rep movsb指令:功能就是根据cx寄存器的值循环实现(cx)次字符的传送
rep movsb
用汇编语法描述上述指令的功能就是:
s:movsb
loop s
- 下面两条指令可以对DF位进行设置
- cld指令:将标志寄存器的DF位置为0
- std指令:将标志寄存器的DF位置为1
11.pushf和popf指令
pushf和popf为直接访问标志寄存器提供了一种方法。
- pushf指令将标志寄存器的值压入栈中
- popf指令从栈中弹出数据,送入标志寄存器中。