汇编
CALL和RET指令:
RET指令
- ret指令:用栈中的数据修改IP,从而实现近转移。使用ret时,相当于pop IP。
- retf指令:用栈中的数据修改CS和IP,从而实现远转移。相当于 pop ip pop cs。
CALL指令
- 根据位移进行的转移:CALL 标号 。 这个指令会将当前IP内的值压入栈,然后再转移到标号处进行指令。相当于 push ip jmp near ptr 标号。
- 转移目的地址在指令中:CALL far ptr 标号。这个指令会将当前的 CS 和 IP 压入栈中,然后转移到标号处进行指令。相当于push CS push IP jmp far ptr 标号。
- 转移地址在寄存器中:CALL 16位寄存器 。 这个指令会将当前的 IP 压入栈中 ,然后转移到 IP 为16位寄存器中的值的地方执行指令。相当于 push IP jmp 16位寄存器。
- 转移地址在内存中:call word ptr 内存单元地址,call dword ptr 内存单元地址。前者先将IP压入栈中,然后再从内存单元中读取一个字作为偏移地址,然后转到偏移地址所在的地方执行指令,相当于 push ip jmp word ptr 内存单位 。后者先将CS压入栈中,然后再将IP压入栈中。然后从指定内存单元开始读取两个字,高位字节作为CS的值,低位字节作为IP的值。然后转到CS:IP指定的地方执行指令,相当于 push cs push ip jmp dword ptr 内存单位。
CALL 和 RET 的配合使用
把这两者配合使用,可以实现类似于c++中的函数调用,在汇编中我们称其为子程序。
我们来分析一下这个程序
以后我们可以用类似的方法来创建子程序,大体框架为:
子程序标号:子程序内容.....
..........
ret
start: 主程序内容......
..........
call 子程序标号 (需要调用子程序的地方)
主程序内容......
...........
子程序和主程序的位置关系没有要求。
参数和结果传递的问题:
我们既然创建了子程序,那么就会有参数传递,以及返回结果的问题。我们一般会将参数和结果都放在寄存器中进行传递。
MUL指令:
mul 为乘法指令。
当两个因子都为8位的话(二进制),那么就用8位寄存器,其中一个因子默认在AL中,另一个可以在一个8位寄存器中,也可以在内存单元中,内存单元可以用不同的寻址方式给出。可以是 mul byte ptr ds:[0] 也可以是 mul byte ptr [bx] .
当两个因子中至少有一个为16位的话(二进制),那么就用16位寄存器,其中一个因子默认在AX中,另一个可以在一个16位寄存器中,也可以在内存单元中,内存单元也可以用不同的寻址方式给出。但 byte ptr 要换成 word ptr 。
对于结果:
只要结果没超过16位,那么就放在AX中,超过了,高位放在DX中,低位放在AX中。
这里我把另一个因子放在了bx中。我们可以看到,两个8位的数据,相乘结果大于8位小于16位,放在了AX中。
一个8位的数据和一个16位的数据相乘,结果大于8位,小于16位,放在了AX中。
批量数据传递:
当要传递的数据有很多个时,寄存器会不够用,这时我们可以把参数储存在内存中,用访问内存的形式来传递参数。
比如类似于这样,只要我们把存放参数的那个位置的段地址存入DS中就可以了。
解决除法溢出问题:
取商运算符 int() 如int (28/6)= 4
取余运算符 rem() 如 rem(28/6) =4
汇编
CALL和RET指令:
RET指令
- ret指令:用栈中的数据修改IP,从而实现近转移。使用ret时,相当于pop IP。
- retf指令:用栈中的数据修改CS和IP,从而实现远转移。相当于 pop ip pop cs。
CALL指令
- 根据位移进行的转移:CALL 标号 。 这个指令会将当前IP内的值压入栈,然后再转移到标号处进行指令。相当于 push ip jmp near ptr 标号。
- 转移目的地址在指令中:CALL far ptr 标号。这个指令会将当前的 CS 和 IP 压入栈中,然后转移到标号处进行指令。相当于push CS push IP jmp far ptr 标号。
- 转移地址在寄存器中:CALL 16位寄存器 。 这个指令会将当前的 IP 压入栈中 ,然后转移到 IP 为16位寄存器中的值的地方执行指令。相当于 push IP jmp 16位寄存器。
- 转移地址在内存中:call word ptr 内存单元地址,call dword ptr 内存单元地址。前者先将IP压入栈中,然后再从内存单元中读取一个字作为偏移地址,然后转到偏移地址所在的地方执行指令,相当于 push ip jmp word ptr 内存单位 。后者先将CS压入栈中,然后再将IP压入栈中。然后从指定内存单元开始读取两个字,高位字节作为CS的值,低位字节作为IP的值。然后转到CS:IP指定的地方执行指令,相当于 push cs push ip jmp dword ptr 内存单位。
CALL 和 RET 的配合使用
把这两者配合使用,可以实现类似于c++中的函数调用,在汇编中我们称其为子程序。
我们来分析一下这个程序
以后我们可以用类似的方法来创建子程序,大体框架为:
子程序标号:子程序内容.....
..........
ret
start: 主程序内容......
..........
call 子程序标号 (需要调用子程序的地方)
主程序内容......
...........
子程序和主程序的位置关系没有要求。
参数和结果传递的问题:
我们既然创建了子程序,那么就会有参数传递,以及返回结果的问题。我们一般会将参数和结果都放在寄存器中进行传递。
MUL指令:
mul 为乘法指令。
当两个因子都为8位的话(二进制),那么就用8位寄存器,其中一个因子默认在AL中,另一个可以在一个8位寄存器中,也可以在内存单元中,内存单元可以用不同的寻址方式给出。可以是 mul byte ptr ds:[0] 也可以是 mul byte ptr [bx] .
当两个因子中至少有一个为16位的话(二进制),那么就用16位寄存器,其中一个因子默认在AX中,另一个可以在一个16位寄存器中,也可以在内存单元中,内存单元也可以用不同的寻址方式给出。但 byte ptr 要换成 word ptr 。
对于结果:
只要结果没超过16位,那么就放在AX中,超过了,高位放在DX中,低位放在AX中。
这里我把另一个因子放在了bx中。我们可以看到,两个8位的数据,相乘结果大于8位小于16位,放在了AX中。
一个8位的数据和一个16位的数据相乘,结果大于8位,小于16位,放在了AX中。
批量数据传递:
当要传递的数据有很多个时,寄存器会不够用,这时我们可以把参数储存在内存中,用访问内存的形式来传递参数。
比如类似于这样,只要我们把存放参数的那个位置的段地址存入DS中就可以了。
解决除法溢出问题:
取商运算符 int() 如int (28/6)= 4
取余运算符 rem() 如 rem(28/6) =4