CALL和RET指令
call和ret属于转移指令,都修改IP或者CS,IP。进程用来设计子程序,也就是函数
ret和retf
ret指令用栈中的数据来修改IP,实现近转移
retf指令用栈中的数据来修改cs和ip,实现远跳转
ret
在汇编中执行ret的指令时,需要进行两步操作
(ip)=((ss)*16+(sp))
(sp)=(sp+2)
意思就是把当前栈的东西送给ip,然后再栈顶指针下移,相当于就是pop ip
retf
执行retf指令时分为四步操作:
1 (ip)=((ss)*16+(sp))
2 (sp)=(sp)+2
3 (CS)=((ss)*16+(sp))
4 (sp)=(sp)+2
相当于:
pop ip
pop cs
例:
assume cs:code,ss:stack
stack segment
db 16 dup (0)
stack ends
code segment
mov ax,4c00h
int 21h
start:
mov ax,stack
mov ss,ax
mov sp,16
;init stack
mov ax,0
push ax
mov bx,0
ret
code ends
end start
这个程序表示的意思就是ret执行后,cs:ip跳转到第一条指令来执行
assume cs:code,ss:stack
stack segment
db 16 dup (0)
stack ends
code segment
mov ax,4c00h
int 21h
start:
mov ax,stack
mov ss,ax
mov sp,16
; init stack
mov ax,0
push cs
push ax
mov bx,0
retf
code ends
end start
执行retf后,回到了第一条指令
实现从内存1000:0000开始执行指令
stack segment
db 16 dup (0)
stack ends
code segment
assume cs:code,ss:stack
start:
mov ax,stack
mov ss,ax
mov sp,16
;init stack
mov ax,1000h
push ax
mov ax,0000h
push ax
retf
code ends
end start
CALL指令
CPU执行call指令时要进行两步操作
1 将当前的ip或者cs:ip入栈
2 转移
call指令不能断跳转,除此之外call指针实现转移的原理和jmp相同
依据位移进程转移的call指令
call标号(将当前的IP压栈后跳转到标号)
CPU执行CALL指令后进行的操作:
(sp)=(sp)-2
((ss)*16+(sp))=(ip)
(ip)=(ip)+16位位移
相当于进行了
push ip
jmp near ptr 标号
call标号
16位位移=“标号”最小的地址-call指令后的第一个字节的地址
16位范围
-32768~32767
例:
1000:0 mov ax,0
1000:3 call s
1000:6 inc ax
1000:7s: pop ax
这个程序执行后ax等于6
转移的目的地址在指令中的call指令
call far ptr 标号实现的是段间转移
CPU执行此种格式的call指令时,执行以下操作:
(sp)=(sp)-2
((ss)*16+(sp))=(cs)
(sp)=(sp)-2
((ss)*16+(sp))=(IP)
(CS)=标号的段地址
(IP)=标号的便宜偏移地址
执行call far ptr标号就相当于
push CS
push IP
jmp far ptr标号
例:
1000:0 mov ax,0
1000:3 call far ptr s
1000:8 inc ax
1000:9s:
pop ax
add ax,ax
pop bx
add ax,bx
执行完之后 ax=10h bx=1010h
转移地址在寄存器中的call指令
格式:call reg16
功能:
(sp)=(sp)-2
((ss)*16+(sp))=(ip)
(ip)=reg16
用汇编来描述就是
push IP
jmp reg16
例:
1000:0 mov ax,6 ;ax=6
1000:3 call ax
1000:5 inc ax
1000:6 mov bp,sp ;跳转到这里ip=5
;相当于push 5
add ax,[bp] ;6+5=11
ax=0bh
转移地址在内存中的call指令
转移地址在内存中有两种格式:
第一种格式
1 call word ptr 内存单元地址
用汇编来解释就是
push IP
jmp word ptr 内存单元地址
;例
mov sp,10h
mov ax,0123h
mov ds:[0],ax
call word ptr ds:[0]
执行后(IP)=0123h,(sp)=0Eh
第二种格式
call dword ptr
相当于执行
push CS
push IP
jmp dword ptr 内存单元地址
CS
;例
mov sp,10h
mov ax,0123h
mov ds:[0],ax
mov word ptr ds:[2],0
call dword ptr ds:[0]
(cs)=0,(IP)=0123h,(sp)=0CH
CS在高位,IP在低位
例
stack segment
dw 8 dup (0)
stack ends
code segment
assume cs:code,ss:stack
start:
mov ax,stack
mov ss,ax
mov sp,16
;init stack
mov ds,ax
mov ax,0
call word ptr ds:[0EH] ;跳转到栈顶修改IP的值
;push ip=inc ax的地址
inc ax
inc ax
inc ax
mov ax,4c00h
int 21h
code ends
end start
call和ret的配合使用
分析第一个简单程序
code segment
assume cs:code
start:
mov ax,1
mov cx,3 ;表示循环3次
call s
mov bx,ax ;bx=8
mov ax,4c00h
int 21h
s: add ax,ax
loop s
ret ;返回时ax=8
code ends
end start
分析第二个程序
assume cs:code
stack segment
db 8 dup (0)
db 8 dup (0)
stack ends
code segment
start:
mov ax,stack
mov ss,ax
mov sp,16
;init stack
mov ax,1000
call s
mov ax,4c00h
int 21h
s:
add ax,ax
ret
code ends
end start
其实就和设计函数差不多
模块化程序设计
利用call和ret来进行各种函数子进程的编写来达成模块化的程序设计
参数和结果传递的问题
通常利用寄存器和栈来存储函数的各种内容,比如参数,返回值等等