汇编入门学习笔记 —— call和ret

Posted wzjhoutai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了汇编入门学习笔记 —— call和ret相关的知识,希望对你有一定的参考价值。

疯狂的暑假学习之  汇编入门学习笔记 (九)——  call和ret


參考: 《汇编语言》 王爽 第10章


call和ret都是转移指令。


1. ret和retf


ret指令:用栈中的数据,改动IP内容,从而实现近转移

相当于:

pop ip

retf指令:用栈中的数据。改动CS和IP,从而实现远转移

相当于:

pop ip

pop cs


样例:ret

assume cs:code,ss:stack

stack segment
	db 16 dup(1)
stack ends

code segment
	mov ax,4c00H
	int 21H

start:	mov ax,stack
	mov ss,ax
	mov sp,16
	
	mov ax,0
	push ax
	ret
	
code ends

end start

retf

assume cs:code,ss:stack

stack segment
	db 16 dup(1)
stack ends

code segment
	mov ax,4c00H
	int 21H

start:	mov ax,stack
	mov ss,ax
	mov sp,16
	
	mov ax,0
	push cs
	push ax
		
	retf
	
code ends

end start


2. call指令


call指令,运行操作:

    1.将当前IP或CS和IP压入栈中

    2.跳转


(1)根据位移进行转移的call指令


格式: call 标号


将下一条的指令的ip压入栈中。在转到标号处


相当于:


push ip

jmp near ptr 标号



(2)转移的目的地址在指令中的call指令


格式:

call far ptr 标号


将下一条的指令的CS和IP压入栈中。在转到标号处


相当于:

push cs

push ip

jmp far ptr


(3)转移地址地址在寄存器中的call指令


格式:call 16位reg


相当于:

push ip

jmp 16位reg


(4)转移地址在内存中的call指令

   1. call word ptr 内存单元

        相当于:

             push ip

             jmp word ptr 内存单元

   2. call dword ptr 内存单元

        相当于:

              push cs

              push ip

              jmp dword ptr 内存单元


3. mul 指令


mul 是乘法指令


表示两个数相乘,它必须是都是8位或者都是16位


8位相乘 结果默认存放在ax中

16位相乘 结果高位存放在dx中。低位存放在ax中

样例见以下。



3. call和ret配合使用


call于ret结合使用。就相当于函数。 


样例:求dw中数值的3次方。把bx当做“函数”參数,ax当做“函数”的返回值。

assume cs:code,ds:data

data segment
	dw 1,2,3,4,5,6,7,8
	dd 0,0,0,0,0,0,0,0
data ends

code segment
	start:	mov ax,data
		mov ds,ax
		
		mov si,0
		mov di,16
		mov cx,8
	s:	mov bx,ds:[si]
		call cube
		mov ds:[di],ax
		mov ds:[di+2],dx
		
		add si,2
		add di,4
		loop s
			
		mov ax,4c00H
		int 21H
			
			
	cube:	mov ax,bx
		mul bx
		mul bx
		ret
			
				
code ends

end start


寄存器数量有限,假设要传的參数。或者返回的參数过多。

能够使用内存,或者栈。


样例:小写转大写。(用内存存放參数)


assume cs:code,ds:data

data segment
	db ‘conversation‘
data ends

code segment
	start:	mov ax,data
		mov ds,ax
		
		mov si,0
		mov cx,12
		call captial
		
		mov ax,4c00H
		int 21H
			
captial:and byte ptr ds:[si],11011111b
		inc si
		loop captial
			
code ends

end start


样例:计算 (a - b) ^3  如果a=3,b=1 (用栈来存放參数)

assume cs:code

code segment
	start:	mov ax,1
		push ax
		mov ax,3
		push ax
		call difcube
		
		mov ax,4c00H
		int 21H
		
difcube:push bp
		mov bp,sp
		mov ax,[bp+4]
		sub ax,[bp+6]
		mov bp,ax
		mul bp
		mul bp
		pop bp
		
		ret 4
code ends

end start


上面代码中的 ret 4 表示:

pop ip

add sp,n


样例:小写转大写,用0结尾来推断。(用栈来处理寄存器冲突)

assume cs:code,ds:data

data segment
	db ‘word‘,0
	db ‘city‘,0
	db ‘good‘,0
data ends

code segment
	start:	mov ax,data
		mov ds,ax
		mov cx,3
		
		mov bx,0
	s:	push cx
		mov si,bx
		call capital
		add bx,5
		pop cx
		loop s
			
		mov ax,4c00H
		int 21H
			
capital:mov cl,[si]
		mov ch,0
		jcxz ok
		and byte ptr [si],11011111b
		inc si
		jmp short capital
		ok:	ret		
code ends

end start

注意:要用栈保存cx



样例:实现show_str “函数”  在屏幕显示字符串。

用dh指定函数 。dl指定列号,cl指定颜色

assume cs:code,ds:data,ss:stack

data segment
	db ‘Welcome to masm!‘,0
data ends

stack segment
	dw 8 dup(0)
stack ends

code segment
	start:	mov ax,data
		mov ds,ax
		mov ax,stack
		mov ss,ax
		mov sp,16
		
		mov dh,10  ;行
		mov dl,17  ;列
		mov cl,2   ;颜色
		mov si,0
		call show_str
			
		mov ax,4c00h
		int 21h
		
show_str:	push ax
		push di
		push dx
			
		mov ax,10   ;确定行段 es
		mul dh
		add ax,0b800h
		mov es,ax
		
		mov dh,0    ;确定列偏移 di,注意。一个字符两个字节
		add dx,dx
		mov di,dx
			
			
	s: 	push cx    ;保存cx
			
		mov ch,0
		mov cl,ds:[si]
		jcxz ok      ;假设为0 跳转
		
		mov es:[di],cl
		pop cx
		mov es:[di+1],cl
		
		inc si
		add di,2
		jmp short s
			
			
			
	ok:	pop cx    ;不要忘记pop,眼不让rec还原的ip就不正确了
		pop dx
		pop di
		pop ax
		ret
			

code ends

end start





以上是关于汇编入门学习笔记 —— call和ret的主要内容,如果未能解决你的问题,请参考以下文章

汇编指令学习(CALL,JMP,RET)

关于汇编指令call和ret的具体细节操作!

汇编语言——call 和 ret 指令

汇编10:CALL和RET指令

汇编-10.0-CALL和RET指令

8086汇编之 CALL 和 RET指令