call指令和ret指令
call 標(biāo)號
-
執(zhí)行方式
- 將嚇一條指令的地址入棧
- 跳轉(zhuǎn)到定位的地址執(zhí)行指令
ret
將棧頂?shù)闹祊op給IP
函數(shù)調(diào)用
1倘潜、 函數(shù)被調(diào)用之前,如果有參數(shù),參數(shù)先入棧唐瀑,然后調(diào)用call指令。
2、 call指令會將下一句指令的內(nèi)存地址入棧
3鸽照、 保護(hù)bp,將bp的值入棧
4、 將sp的值傳遞給bp 颠悬。mov bp,sp
5矮燎、 預(yù)留出存放局部變量的棧空間 sub sp,20h,具體預(yù)留多少空間有編譯器決定
6赔癌、寄存器保護(hù)
7诞外、業(yè)務(wù)代碼
8、寄存器恢復(fù)
9灾票、釋放局部變量占用的空間add sp,20h
10峡谊、釋放bp,pop bp
12刊苍、ret,釋放參數(shù)既们。
圖解
不帶參數(shù)的函數(shù)
assume cs:code
code segment
start:
mov ax,0001h
mov ds,ax
mov [0],0xff
mov [1],0xff
mov [2],0xff
call function;先將 mov ah,4ch的地址入棧,然后執(zhí)行function
mov ah,4ch
int 21h
code ends
function:
mov bx,0h
mov dx,0h
mov cx,3h
s: mov al,[bx]
mov ah,0h
add dx,ax
add bx,1h
loop s
ret ;棧中地址pop給IP
end start
帶參數(shù)正什,帶局部變量的函數(shù)調(diào)用
完整寫法
assume cs:code,ds:data,ss:stack
stack segment
db 40 dup(1)
stack ends
data segment
db 20 dup(0)
str db "Hello world!$"
data ends
code segment
start:
mov ax,stack
mov ss,ax
mov ax,data
mov ds,ax
; mov dx,offset str
; mov ah,9h
; int 21h
push 1h
push 2h
call sum
mov ah,4ch
int 21h
sum:
push bp
mov bp,sp
sub sp,20h
push 3h
push 4h
;業(yè)務(wù)代碼
mov ax,[bp - 2]
add ax,[bp - 4]
add ax,[bp + 2]
add ax,[bp + 4]
add sp,20h
mov sp,bp
pop bp
ret 4
ends
end start
; int result = sum(1,2);
; int sum(int a,int b){
; int c = 3;
; int d = 4;
; return a + b + c + d;
;}
arm64
- 在xdoce下啥纸,函數(shù)內(nèi)部調(diào)用函數(shù),sp上移留出保存參數(shù)婴氮,局部變量的內(nèi)存空間
如果內(nèi)部沒有調(diào)用函數(shù)則sp不會上移斯棒,而是預(yù)留最大128k的紅色區(qū)域(為了優(yōu)化盾致,因?yàn)椴挥迷诒Wo(hù)bp、改變sp荣暮,減少指令)庭惜。如果其參數(shù),局部變量大于128k渠驼,則sp上移增加額外的內(nèi)存 - 編譯器優(yōu)化:release模式下蜈块,編譯器優(yōu)化,如果過程簡單迷扇,直接算出結(jié)果
百揭,函數(shù)會被優(yōu)化,但是oc方法不會蜓席;局部變量可以被優(yōu)化 - 匯編里面方法調(diào)用器一,至少傳兩個(gè)參數(shù):self,cmd(sel)
- 64位CPU由于寄存器多厨内,函數(shù)調(diào)用時(shí)優(yōu)先使用寄存器祈秕。但是,最多有6個(gè)寄存器放參數(shù)雏胃,多余的參數(shù)會放到椙朊空間
棧幀
- stack frame
- 函數(shù)調(diào)用時(shí),sp與bp之間的空間瞭亮;不是每一個(gè)函數(shù)都有棧幀的方仿,比如x86函數(shù)優(yōu)化時(shí)就沒有