接著上一篇文章, 這篇主要講匯編程序中函數(shù)的調(diào)用.
call 和 ret 指令: 函數(shù)的調(diào)用.
- call 標(biāo)號(hào) : 將下一條指令的偏移地址入棧后, 轉(zhuǎn)到標(biāo)號(hào)處執(zhí)行指令
- ret : 將棧頂?shù)闹党鰲? 賦值給 ip.
下面是代碼的一部分, 功能是 調(diào)用 print '函數(shù)', 打印字符串
; 代碼段
code segment
start:
; 手動(dòng)設(shè)置ds, ss 的值
mov ax, data
mov ds, ax
mov ax, stack
mov ss, ax
; 業(yè)務(wù)邏輯
call print
; 程序退出
mov ah, 4ch
int 21h
; 如果這里程序不退出, 它會(huì)繼續(xù)向下執(zhí)行 print 這個(gè)函數(shù), 'print' 在這里只是相當(dāng)于一個(gè)標(biāo)志
print:
; ds: dx 告知字符串地址
lea dx, string
mov ah, 9h ; 功能號(hào) 9h 指在屏幕上顯示字符串
int 21h ; 執(zhí)行 DOS 系統(tǒng)功能調(diào)用.
ret
code ends
end start
我需要說(shuō)明的幾點(diǎn)
-
call print,
print
這里就是一個(gè)標(biāo)號(hào)(函數(shù)名),call
將下一條指令的偏移地址入棧后, 轉(zhuǎn)到 print 處執(zhí)行指令, 這個(gè)下一條指令
就是mov ah, 4ch
. - 當(dāng) print 處的代碼執(zhí)行完后, 每個(gè)函數(shù)都會(huì)有一個(gè) ret 指令, 這個(gè)指令會(huì)將棧頂?shù)闹党鰲? 棧頂?shù)闹稻褪?
mov ah, 4ch
這條指令的偏移地址, 賦值給 ip. 導(dǎo)致 print 函數(shù)執(zhí)行完后, 可以繼續(xù)向下執(zhí)行其他的指令.
函數(shù)調(diào)用的整個(gè)流程
assume cs:code, ds:data, ss:stack
; 棧段
stack segment
db 100 dup(0)
stack ends
; 數(shù)據(jù)段
data segment
db 100 dup(0)
data ends
; 代碼段
code segment
start:
; 手動(dòng)設(shè)置ds哄褒、ss的值
mov ax, data
mov ds, ax
mov ax, stack
mov ss, ax
mov si, 1
mov di, 2
mov bx, 3
mov bp, 4
; 業(yè)務(wù)邏輯
push 1
push 2
call sum
add sp, 4
; 退出
mov ax, 4c00h
int 21h
; 返回值放ax寄存器
; 傳遞2個(gè)參數(shù)(放入棧中)
sum:
; 保護(hù)bp
push bp
; 保存sp之前的值:指向bp以前的值
mov bp, sp
; 預(yù)留10個(gè)字節(jié)的空間給局部變量
sub sp, 10
; 保護(hù)可能會(huì)用到的寄存器
push si
push di
push bx
; 給局部變量空間填充int 3(CCCC)
; stosw的作用:將ax的值拷貝到es:di中,同時(shí)di的值會(huì)+2
mov ax, 0cccch
; 讓es等于ss
mov bx, ss
mov es, bx
; 讓di等于bp-10(局部變量地址最小的區(qū)域)
mov di, bp
sub di, 10
; cx決定了stosw的執(zhí)行次數(shù)
mov cx, 5
rep stosw
; rep的作用:重復(fù)執(zhí)行某個(gè)指令(執(zhí)行次數(shù)由cx決定)
; -------- 業(yè)務(wù)邏輯 - begin
; 定義2個(gè)局部變量
mov word ptr ss:[bp-2], 3
mov word ptr ss:[bp-4], 4
mov ax, ss:[bp-2]
add ax, ss:[bp-4]
mov ss:[bp-6], ax
; 訪問(wèn)棧中的參數(shù)
mov ax, ss:[bp+4]
add ax, ss:[bp+6]
add ax, ss:[bp-6]
; -------- 業(yè)務(wù)邏輯 - end
; 恢復(fù)寄存器的值
pop bx
pop di
pop si
; 恢復(fù)sp
mov sp, bp
; 恢復(fù)bp
pop bp
ret
code ends
end start
說(shuō)明
- 1.push 參數(shù)
- 2.push 函數(shù)的返回地址
- 3.push bp (保留bp之前的值嚼沿,方便以后恢復(fù))
- 4.mov bp, sp (保留sp之前的值匀们,方便以后恢復(fù)), SP 棧頂指針寄存器, BP, 基址指針寄存器
- 5.sub sp,空間大小 (分配空間給局部變量)
- 6.保護(hù)可能要用到的寄存器
- 7.使用CC ( int 3) 填充局部變量的空間
- 8.--------執(zhí)行業(yè)務(wù)邏輯--------
- 9.恢復(fù)寄存器之前的值
- 10.mov sp, bp (恢復(fù)sp之前的值)
- 11.pop bp (恢復(fù)bp之前的值)
- 12.ret (將函數(shù)的返回地址出棧尺棋,執(zhí)行下一條指令)
- 13.恢復(fù)棧平衡 (add sp,參數(shù)所占的空間)
- 棧平衡: 函數(shù)調(diào)用前后的棧頂指針要一致. 棧如果不平衡, 椕2兀空間遲早會(huì)被用完.
- 棧平衡分內(nèi)平棧 和 外平棧
棧幀 (Stack Frame Layout)
棧幀是一個(gè)函數(shù)執(zhí)行的環(huán)境, 包括參數(shù), 局部變量, 返回地址
- 由 下 到 上地址逐漸減小
- 棧幀 3 調(diào)用 棧幀2, 棧幀2 調(diào)用 棧幀 1, 棧幀1 執(zhí)行完后, 被釋放, SP, BP 逐漸增大
注意: 方向和上面是相反的.