call和ret指令都是轉移指令,它們經常被共同用來實現子程式的設計。
ret指令用棧中的資料實現修改ip的內容,從而完成近轉移,執行ret指令時相當於執行:
pop ip
retf指令用棧中的資料實現修改cs和ip的內容,從而完成遠轉移,執行retf指令相當於執行:
pop ip
pop cs
在程式中就可以使用這兩個指令來轉移:
code segment
mov ax,4c00h
int 21h
start: ...
...ret
code ends
end start
這樣由於ret指令的執行,就會讓cs:ip指向**段的第一條指令,完成返回。
call指令執行後進行兩步操作:
1、將當前的ip或cs和ip壓入棧中
2、轉移
call指令可以轉到標號處,同時將當前的ip壓入棧中:
call 標號
相當於執行:
push ip
jmp near ptr 標號
這個指令對應的機器碼中有相對於當前ip的轉移位移。
對應的段間轉移指令:
call far ptr 標號
相當於執行:
push cs
push ip
jmp far ptr 標號
這個指令對應的機器碼中有轉移的目的位址。
call指令後也可以跟暫存器:
call 16位reg
相當於執行:
push ip
jmp 16位reg
1、段內轉移:
call word ptr 記憶體單元位址
相當於執行:
push ip
jmp word ptr 記憶體單元位址
2、段間轉移:
call dword ptr 記憶體單元位址
相當於執行:
push cs
push ip
jmp dword ptr 記憶體單元位址
結合ret和call指令我們可以總結乙個實現子程式的框架:
assume cs:code
code segment
main: ...
...call sub1 呼叫了子程式sub1
......
mov ax,4c00h
int 21h
sub1: ...
...call sub2 呼叫了子程式sub2
...ret sub1返回
sub2: ...
...ret sub2返回
code ends
end main
使用格式:
mul reg
mul 記憶體單元
涉及記憶體單元時,可以中間加word ptr或byte ptr來指定處理的資料長度。
乘法指令中兩個相乘的數要麼都是8位,要麼都是16位;如果都是8位,則乙個預設放在al暫存器中;如果都是16位,則乙個預設放在ax暫存器中。
如果是8位乘法那麼結果預設放在ax中,如果是16位乘法,那麼高位預設放在dx中,低位放在ax中。
有了子程式我們就可以實現組合語言程式設計的模組化設計。
在使用子程式時有兩個問題:引數存在**?結果存在**?
最常見的方法是使用暫存器,呼叫子程式者將引數送入引數暫存器,從結果暫存器中取到返回值;子程式從引數暫存器中取到引數,將返回值送入結果暫存器。
如果我們要傳遞更多的引數怎麼辦?我們不可能都用暫存器來完成傳遞,因為暫存器的個數終究是有限的。
這個時候常用的做法是將批量資料放到記憶體中,然後將他們所在記憶體空間的首位址放在暫存器中,傳遞給需要的子程式。對於多個返回結果,我們也可以用同樣的方法。
棧也可以用來完成這一類任務。
有時程式中會出現暫存器衝突問題,如在乙個迴圈中呼叫某個子程式,子程式中也有迴圈,這些迴圈共用乙個cx暫存器來計數,就會導致迴圈次數的混亂。此時正確的做法應該是在子程式的開始將子程式中所有用到的暫存器中的內容都儲存起來,在子程式返回前都恢復。
案例需求:把資料段中的所有字串都轉換為大寫:
assume cs:code
data segment
db 'word',0
db 'unix',0
db 'wind',0
db 'good',0
data ends
capital:mov cl,[si]
mov ch,0
jcxz ok 如果cx為0,就結束
and byte ptr [si],11011111b 否則就將該字母轉換為大寫,然後再將si自增
inc si
jmp short capital
ok: ret
但是這個子程式沒有完成環境儲存,所以需要再改動一下,加上資料恢復和取用:
capital:push cx
push si
change: mov cl,[si]
mov ch,0
jcxz ok 如果cx為0,就結束
and byte ptr [si],11011111b 否則就將該字母轉換為大寫,然後再將si自增
inc si
jmp short change
ok: pop si
pop cx
ret
然後再呼叫該子程式即可:
code segment
start: mov ax,data
mov ds,ax
mov bx,0 指定總的迴圈次數
mov cx,4
s: mov si,bx 處理字串,然後將指標加5,處理下乙個字串
call capital
add bx,5
loop s
mov ax,4c00h
int 21h
capital:push cx
push si
change: mov cl,[si]
mov ch,0
jcxz ok 如果cx為0,就結束
and byte ptr [si],11011111b 否則就將該字母轉換為大寫,然後再將si自增
inc si
jmp short change
ok: pop si
pop cx
retcode ends
end start
組合語言 CALL 和RET指令
call和ret指令都是轉移指令,它們都修改ip,但同時修改cs和ip。ret指令用棧中的資料,修改ip的內容,從而實現近轉移。retf指令用棧中的資料,修改cs和ip的內容,從而實現遠轉移。cpu執行ret指令時,進行下面兩步操作 ip ss 16 sp sp sp 2 cpu執行retf指令時,...
組合語言 call和ret指令
call和ret指令都是轉移指令,它們都修改ip,或同時修改cs和ip。它們經常被共同用來實現子程式的設計。ret指令用棧中的資料,修改ip的內容,從而實現近轉移 retf指令用棧中的資料,修改cs和ip的內容,從而實現遠轉移 cpu執行ret指令時,進行下面兩步操作 cpu執行retf指令時,進行...
第10章 call和ret指令
引言 call和ret都是轉移指令,他們都修改ip,或同時修改cs和ip。他們經常被共同用來實現程式的設計 10.1 ret和retf ret指令用棧中的資料,修改ip的內容,從而實現近轉移。retf指令用棧中的資料,修改cs和ip的內容,從而實現遠轉移 可以看出,如果我們用彙編語法來解釋ret和r...