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