《組合語言(第三版)》王爽筆記(10)CALL和RET指令
第十章 CALL和RET指令
call和ret也是轉移指令,它們都修改IP或同時修改CS和IP。他們經常被共同用來實現子程式設計。
ret指令用棧中資料修改IP,實現近轉移。使用方法:ret retf指令用棧中資料修改CS和IP,實現遠轉移。使用方法:retf CPU執行ret時,操作如下: (IP) = ((ss * 16)+sp) (sp) = (sp)+2 相當於進行 pop ip CPU執行retf時,操作如下: (IP) = ((ss * 16)+sp) (sp) = (sp)+2 (CS) = ((ss * 16)+sp) (sp) = (sp)+2 相當於進行 pop ip pop cs
檢測點10.1
1000h 0
CPU執行call指令: (1)將當前的IP或CS和IP壓入棧中。 (2)轉移。 call指令不能實現短轉移,其他與jmp類似。具體分類如下: call 標號(將當前IP壓棧,轉到標號處執行指令)(對應的機器指令中沒有目的地址,只有相對轉移位移) (sp) = (sp)-2 ((ss*16)+sp) = (IP) (IP) = (IP)+16位位移 16位位移 = 標號處地址- call指令後第一個位元組的地址 (-32768-32767) 相當於進行 push ip jmp near ptr 標號
檢測點10.2
6(執行完call s後,IP先變為6,然後將IP的值壓棧,最後跳轉至s)
call far ptr 標號(對應機器指令中有轉移的目的地址) 段間轉移,執行: (sp) = (sp)-2 ((ss * 16)+sp) = (CS) (sp) = (sp)-2 ((ss * 16)+sp) = (IP) (CS)=(標號所在段的段地址) (IP)=(標號在段中的偏移地址) 相當於進行 push cs push ip jmp far ptr 標號
檢測點10.3
1010H(執行完call far ptr s後,IP先變為8,然後將CS、IP的值分別為1000和8依此壓棧,最後再跳轉至s繼續執行)
call 16位reg(轉移地址在暫存器中) 執行: (sp) = (sp)-2 ((ss * 16)+sp) = (IP) (IP) = (16位reg) 相當於 push ip jmp 16位reg
檢測點10.4
0BH
轉移地址在記憶體中: call word ptr 記憶體單元地址 相當於 push ip jmp word ptr 記憶體單元地址 call dword ptr 記憶體單元地址 相當於 push cs push ip jmp dword ptr 記憶體單元地址
檢測點10.5
(1)3(ds與ss中存放的段地址相同,在執行了call word ptr ds:[0EH]之後,程式會先將下一條指令inc ax的偏移量壓棧,然後從ds:[0EH]讀取兩個記憶體單元作為IP的值,即剛剛壓入的指令inc ax的偏移地址,CS:IP從inc ax繼續執行,故最後ax的值為3。) (2)ax=1,bx=0 (程式的一開始將s的偏移量和cs放入ss:[0]和ss:[2]中,然後呼叫call指令,將CS和IP(nop指令的偏移量)依此壓棧後(sp = 0ch)跳轉到s處繼續執行,ax最終為s的偏移量減去nop指令所在位置的偏移量,為1,bx最終為cs的段地址相減,為0。)
程式返回前,(bx) = 8。從s到ret實現了計算2的N次方,N由cx提供。
子程式:具有某些功能的一段程式,在需要的時候用call轉去執行,在子程式後加入ret,實現執行子程式後轉回call之後的指令繼續執行。 具有子程式的程式框架:
assume cs:code
code segment
main:
...
call sub1 ;呼叫子程式sub1
...
mov ax,4c00h
int 21h
sub1: ;子程式sub1開始
...
ret ;子程式返回
code ends
end main
mul指令 使用乘法指令需要注意: (1)兩個相乘的數:必須同時為16位或8位,如果是16位,一個在ax中,另一個在16位reg中或記憶體字單元中。如果是8位,一個在al中,一個在8位reg或記憶體位元組單元中。 (2)結果:8位乘法的結果放在ax中,16位乘法的結果高位放dx,低位放ax。 指令: mul reg 或 mul 記憶體單元 待解決問題: 1.如何儲存子程式需要的引數和產生的返回值? 使用暫存器是最常用的一種方法。 2.如何傳遞批量資料? 將批量資料放入記憶體,將他們所在記憶體空間的首地址放在暫存器中,傳遞給子程式。對於有批量返回結果的子程式,也可以採用類似方法。 3.子程式與主程式使用暫存器衝突 使用棧。在子程式使用暫存器前將暫存器中的值儲存起來,在子程式返回之前把這些儲存的值恢復。
實驗10
1.show_str.asm
assume cs:code, ss:stack
stack segment
dw 16 dup (0)
stack ends
data segment
db 'Welcome to masm!',0
data ends
code segment
start:
mov dh,8
mov dl,3
mov cl,2
mov ax,data
mov ds,ax
mov si,0
call show_str
mov ax,4c00h
int 21h
show_str:
push cx
push bx
push ax
push si
push di
push es
;using cx, bx, ax, si, di, es
mov ax, 0b800h
mov es,ax
mov bx,0
mov di,0
mov al,160
mul dh
add bx,ax
mov al,2
mul dl
add bx,ax ;bx stores address of start character
mov al,cl ;al stores the color of character
char:
mov ch,0
mov cl,ds:[si]
jcxz zero
mov ch,al
mov es:[bx+di],cx
add di,2
inc si
jmp char
zero:
pop es
pop di
pop si
pop ax
pop bx
pop cx
ret
code ends
end start
2.divdw.asm
assume cs:code,ss:stack
stack segment
dw 16 dup (0)
stack ends
code segment
start:
mov ax,stack
mov ss,ax
mov sp,32
mov ax,4240h ;L16
mov dx,000fh ;H16
mov cx,0ah
call divdw
mov ax,4c00h
int 21h
divdw:
push bx
;using bx
mov bx,ax ;bx stores L
mov ax,dx ;ax stores H
mov dx,0
div cx ;after div, ax holds int(H/N), dx holds rem(H/N)
push ax ; push int(H/N) temporarily
mov ax,bx ;ax stores L, dx stores rem(H/N)
div cx
mov cx,dx
pop dx ; dx stores int(H/N)
pop bx
ret
code ends
end start
3.dtoc.asm
assume cs:code,ss:stack
stack segment
dw 16 dup (0)
stack ends
data segment
db 10 dup (0)
data ends
code segment
start:
mov ax,12666
mov bx,data
mov ds,bx
mov si,0
call dtoc
mov dh,8
mov dl,3
mov cl,2
call show_str
mov ax,4c00h
int 21h
dtoc:
push ax
push si
push di
push dx
push bx
push cx
mov di,0
mov dx,0
mov bx,10
devide:
mov cx,ax
jcxz stop
div bx
inc di
push dx
mov dx,0
jmp devide
stop:
mov cx,di
string:
pop bx
add bx,30h
mov[si],bl
inc si
loop string
pop cx
pop bx
pop dx
pop di
pop si
pop ax
ret
show_str:
push cx
push bx
push ax
push si
push di
push es
;using cx, bx, ax, si, di, es
mov ax, 0b800h
mov es, ax
mov bx, 0
mov di, 0
mov al, 160
mul dh
add bx, ax
mov al, 2
mul dl
add bx, ax ;bx stores address of start character
mov al, cl ;al stores the color of character
char:
mov ch, 0
mov cl, ds:[si]
jcxz zero
mov ch, al
mov es:[bx+di], cx
add di, 2
inc si
jmp char
zero:
pop es
pop di
pop si
pop ax
pop bx
pop cx
ret
code ends
end start