call和ret指令都是转移指令,它们都修改IP,或同时修改IP和CS
ret和retf:
- ret指令使用栈中数据,修改IP内容,实现近转移。进行两步操作:(1)(IP)= ((ss) * 16 + (sp)) (2) (sp) = (sp) + 2 等价于 pop IP
- retf指令使用栈中数据,修改CS和IP内容,实现远转移。进行四步操作:(1)(IP)= ((ss) * 16 + (sp)) (2) (sp) = (sp) + 2 (3) (CS) = ((ss) * 16 + (sp)) (4)(sp) = (sp) + 2 等价于pop IP pop CS
call指令:
call指令进行两步操作:(1)将当前的IP 或 CS和IP压入栈中;(2)转移(IP对应近转移,CS和IP对应远转移)
依据位移进行的call指令:
- call 标号 进行如下操作:(1)(sp)= (sp) - 2 ((ss) * 16 + (sp)) = (IP) (2)(IP) = (IP) + 16位位移
- 等价于 push IP jmp near ptr 标号
依据地址进行的call指令:
- call far ptr 标号 进行如下操作:(1)(sp)= (sp) - 2 ((ss) * 16 + (sp)) = (CS) (sp) = (sp) - 2 ((ss) * 16 + (sp)) = (IP) (2) (CS)的地址 = 标号所在段的段地址;(IP)的地址 = 标号所在段的偏移地址
- 等价于 push CS push IP jmp far ptr 标号
- call 16 位reg 进行如下操作:(sp)= (sp) - 2 ((ss) * 16 + (sp)) = (IP) (IP) = 16位reg
- 等价于 push IP jmp near 16位reg
- call word ptr 内存单元地址 进行如下操作:(sp) = (sp) - 2 ((ss) * 16 + (sp)) = (IP) (IP) = (内存单元地址中的内容)
- 等价于push IP jmp word ptr 内存单元地址
- call dword ptr 内存单元地址 进行如下操作:(1)(sp)= (sp) - 2 ((ss) * 16 + (sp)) = (CS) (sp) = (sp) - 2 ((ss) * 16 + (sp)) = (IP) (2) (CS)的地址 = 后两字节内容;(IP)的地址 = 前两字节内容
- 等价于push CS push IP jmp dword ptr 内存单元地址
用call和ret实现调用子程序:
- call sub1
- ...(返回处)
- sub 1 :
- .....(子程序)
- ret (返回第二行)
mul乘法指令:
mul reg 或者 mul 内存单元
- 两个数相乘,位数必须相等,要么都是8位(小于255),要么都是16位。不足8位的,可以扩展成16位。
- 8位乘8位时,一个数默认放在AL中,另一位数要么是放在8位寄存器中,要么是在8位内存单元中,最终结果默认在AX中
- 16位乘16位时,一个数默认放在AX中,另一位数要么是放在16位寄存器中,要么是在16位内存单元中,最终结果默认,低16位在AX中,高16位在DX中
主程序和子程序调用同一个寄存器可能会发生冲突,解决这一问题的方法是:
- 在子程序的开头将调用的寄存器入栈,注意不要将此部分加入循环中,可以单独放在开头
- 在子程序返回前将调用的寄存器出栈,注意此部分同样不要加入循环之中,与ret或者retf放在一部分
- 注意出栈和入栈的顺序是相反的