匯編語言-子程序調用
ret與ref指令
ret
ret == pop IP
ret指令用棧中的數據,修改IP的內容,從而實現近轉移;
功能介紹
retf指令用棧中的數據,修改CS和IP的內容,從而實現遠轉移
CPU執行ret指令時,進行下面兩步操作:
(1)(IP) = ((ss) * 16 + (sp)) (2)(sp) = (sp) + 2
相當於進行:
pop IP
retf
retf == pop IP + POP CS
功能介紹
CPU執行retf指令時,進行下面兩步操作:
(1)(IP) = ((ss) * 16 + (sp)) (2)(sp) = (sp) + 2 (3)(CS) = ((ss) * 16 + (sp)) (4)(sp) = (sp) + 2
相當於進行:
pop IP
pop CS
call指令
call 標號
功能介紹
(把當前IP壓棧后, 轉到標號處執行指令)
a. (SP) = (SP) - 2 ((SS) * 16 + SP) = (IP) b. (IP) = (IP) + 16位位移
相當於:
push IP
jmp near ptr 標號
- 16位位移 = “標號”處的地址 - call指令后的第一個字節的地址;
- 16位位移的范圍 -32768—-32767, 用補碼表示;
- 16位位移由編譯程序在編譯時算出;
call far ptr 標號
功能介紹
(把當前CS,IP壓棧后, 轉到標號處執行指令)
a. (SP) = (SP) - 2 ((SS) * 16 + SP) = (CS) b. (SP) = (SP) - 2 ((SS) * 16 + SP) = (IP) c. (CS) = 標號所在段的段地址 (IP) = 標號在段中的偏移地址
相當於:
push CS
push IP
jmp par ptr 標號
call 16位寄存器
功能介紹
(sp) = (sp) – 2 ((ss) * 16 + (sp)) = (IP) (IP) = (16位寄存器)
相當於:
push IP
jmp 16位寄存器
call word ptr 內存單元地址
功能介紹
push IP
jmp word ptr 內存單元地址
實例展示
mov sp, 10h
mov ax, 0123h
mov ds:[0], ax
call word ptr ds:[0]
執行后,(IP)=0123H,(sp)=0EH
call dword ptr 內存單元地址
功能介紹
push CS
push IP
jmp dword ptr 內存單元地址
實例展示
mov sp, 10h
mov ax, 0123h
mov ds:[0], ax
mov word ptr ds:[2], 0
call dword ptr ds:[0]
執行后,(CS)=0,(IP)=0123H,(sp)=0CH
((IP)= ds:[0], (CS) = ds:[2])
子程序調用
通過上面介紹的兩個指令,我們可以完成子程序的調用。簡單調用程序如下:
assume cs:code
code segment
start: mov ax,1
mov cx,3
call s
mov bx, ax
mov ax,4c00H
int 21H
s: add ax,ax
loop s
ret
code ends
end start
子程序調用-傳遞參數問題
我們在寫c語言或者其他高級語言的時候,要經常用到函數之間的參數傳遞這一個概念。那么在匯編語言中,我們怎么做到總程序和子程序之間的參數傳遞呢?
寄存器存放法
首先可以考慮在寄存器中,存放數據,比如a存放在ax中,b存放在bx中。
mov ax,a
mov bx,b
這種方式可以在參數比較少的時候使用,但是參數多了呢?那么那么多的寄存器給你存放。因此這種方式不是長久之計。
內存存放法
我們想到了一個比較好的思路,就是將參數保存到內存中,然后在寄存器中存放這些參數的首地址,通過首地址訪問一系列的參數。這種方式,顯然可以存放更多的數據,並且沒有數量上的限制。
;參數存放段
data segment
db 'aaaaa',0
db 'aaaaa',0
db 'aaaaa',0
data ends
code segment
...
...
mov ax,data
mov es,ax
mov si,0
call sub1
...
...
sub1: mov ax,es[si]
...
...
ret
code ends
這里還是存在一個問題,如果在主程序中用到了一個xx寄存器,然后在子程序中也用到了這個xx寄存器,那么當子程序返回到主程序的時,主程序中存放參數的內存地址已經沒有記錄了,程序出錯。
內存存放法(改進)
為了解決這個問題,我們需要每次進入子程序時,將子程序中的需要用到的寄存器,push到棧中,每次退出子程序時,將相應寄存器pop出來。
子程序都應遵循下面的模式:
capital:
push cx
push si
change:
mov cl,[si]
mov ch,0
jcxz ok
and byte ptr[si],11011111B
inc si
jmp short change
ok:
pop si
pop cx
ret
