1. 程式人生 > >彙編入門學習筆記 (九)—— call和ret

彙編入門學習筆記 (九)—— 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