0x29:call 和 ret 指令
call和ret指令都是转移指令,它们都修改IP,或同时修改CS和IP。
ret 和 retf
- ret指令用栈中的数据,修改IP的内容,从而实现近转移;
- retf指令用栈中的数据,修改CS和IP的内容,从而实现远转移。
CPU执行ret指令时,相当于进行: pop IP
:
(1)(IP) = ( (ss) * 16 + (sp) )
(2)(sp) = (sp) + 2
CPU执行retf指令时,相当于进行:pop IP, pop CS
:
(1)(IP) = ( (ss) * 16 + (sp) )
(2)(sp) = (sp) + 2
(3)(CS) = ( (ss) * 16 + (sp) )
(4)(sp) = (sp) + 2
1 | assume cs:code |
call 指令
call指令经常跟ret指令配合使用,因此CPU执行call指令,进行两步操作:
(1)将当前的 IP 或 CS和IP 压入栈中;
(2)转移(jmp)。
call指令不能实现短转移,除此之外,call指令实现转移的方法和 jmp 指令的原理相同。
call 标号
(近转移)
CPU执行此种格式的call指令时,相当于进行 push IP
jmp near ptr 标号
call far ptr 标号
(段间转移)
CPU执行此种格式的call指令时,相当于进行:push CS,push IP
jmp far ptr 标号
call 16位寄存器
CPU执行此种格式的call指令时,相当于进行: push IP
jmp 16位寄存器
call word ptr 内存单元地址
CPU执行此种格式的call指令时,相当于进行:push IP
jmp word ptr 内存单元地址
练习1:下面程序执行后 ax 的值为多少?
运行到call s
时,指令结束ip = 6
,相当于push [6]
,然后jmp near ptr s
,转到 s ,ax = 6
。
练习2:下面程序执行后 ax 的值为多少?
练习3:
bp 寄存器作用类似 bx,它的默认段寄存器是 ss,当执行call ax
时,ip = 5
入栈,jmp ax
, ss:sp
的内容是5,然后mov bp,sp
,此时[bp] = ss:sp = 5
,最后一步执行完ax = 6h+5h = 0bh
。
call 和 ret 的配合使用
分析下面程序返回前 bx 中的值是多少?
1 | assume cs:code |
我们利用 call 和 ret 可以实现函数的子程序。(一个入栈,一个出栈)
0x30:标志寄存器
CPU内部的寄存器中,有一种特殊的寄存器(对于不同的处理机,个数和结构都可能不同)具有以下3种作用。
(1)用来存储相关指令的某些执行结果;
(2)用来为CPU执行相关指令提供行为依据;
(3)用来控制CPU的相关工作方式。
这种特殊的寄存器在8086CPU中,被称为标志寄存器(flag)。
8086CPU的标志寄存器有16位,其中存储的信息通常被称为程序状态字(PSW-Program Status Word)。
flag寄存器是按位起作用的,它的每一位都有专门的含义,记录特定的信息。
在8086CPU的指令集中,有的指令的执行是影响标志寄存器的,比如,add、sub、mul、div、inc、or、and等,它们大都是运算指令(进行逻辑或算术运算);有的指令的执行对标志寄存器没有影响,比如,mov、push、pop等,它们大都是传送指令。
零标志位 (ZF)
零标志位(Zero Flag)。它记录相关指令执行后,其结果是否为0。
如果结果为0,那么zf = 1(表示结果是0);如果结果不为0,那么zf = 0。
1 | mov ax, 1 |
奇偶标志位 (PF)
奇偶标志位(Parity Flag)。它记录相关指令执行后,其结果的所有bit位中1的个数是否为偶数。
如果1的个数为偶数,pf = 1,如果为奇数,那么pf = 0。
1 | mov al, 1 |
符号标志位(SF)
符号标志位(Symbol Flag)。它记录相关指令执行后,其结果是否为负。
如果结果为负,sf = 1;如果非负,sf = 0。
计算机中通常用补码来表示有符号数据。计算机中的一个数据可以看作是有符号数,也可以看成是无符号数。
00000001B
,可以看作为无符号数1,或有符号数+1;
10000001B
,可以看作为无符号数129,也可以看作有符号数-127。
SF标志,就是CPU对有符号数运算结果的一种记录,它记录数据的正负。在我们将数据当作有符号数来运算的时候,可以通过它来得知结果的正负。如果我们将数据当作无符号数来运算,SF的值则没有意义。
1 | mov al, 10000001B |
进位标志位(CF)
进位标志位(Carry Flag)。一般情况下,在进行无符号数运算的时候,它记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值。
当两个8位数据相加进位时,多出来的进位值并不会丢失,而是存在flag寄存器的CF标志上。
溢出标志位(OF)
溢出标志位(Overflow Flag)。一般情况下,OF记录了有符号数运算的结果是否发生了溢出。
如果发生溢出,OF = 1;如果没有,OF = 0。
CF和OF的区别:CF是对无符号数运算有意义的标志位,而OF是对有符号数运算有意义的标志位
CPU在执行add等指令的时候,就包含了两种含义:无符号数运算和有符号数运算。
- 对于无符号数运算,CPU用CF位来记录是否产生了进位;
- 对于有符号数运算,CPU用OF位来记录是否产生了溢出,当然,还要用SF位来记录结果的符号。
1 | mov al, 98 |
对于每个add指令,有两种解读方式。