匯編語言-子程序調用


匯編語言-子程序調用

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM