call指令和ret指令
call 標號
-
執行方式
- 將嚇一條指令的地址入棧
- 跳轉到定位的地址執行指令
ret
將棧頂的值pop給IP
函數調用
1、 函數被調用之前,如果有參數,參數先入棧,然后調用call指令。
2、 call指令會將下一句指令的內存地址入棧
3、 保護bp,將bp的值入棧
4、 將sp的值傳遞給bp 。mov bp,sp
5、 預留出存放局部變量的棧空間 sub sp,20h,具體預留多少空間有編譯器決定
6、寄存器保護
7、業務代碼
8、寄存器恢復
9、釋放局部變量占用的空間add sp,20h
10、釋放bp,pop bp
12、ret,釋放參數。
圖解
8086_fun.png
不帶參數的函數
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的地址入棧,然后執行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
帶參數,帶局部變量的函數調用
完整寫法
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
;業務代碼
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下,函數內部調用函數,sp上移留出保存參數,局部變量的內存空間
如果內部沒有調用函數則sp不會上移,而是預留最大128k的紅色區域(為了優化,因為不用在保護bp、改變sp,減少指令)。如果其參數,局部變量大于128k,則sp上移增加額外的內存 - 編譯器優化:release模式下,編譯器優化,如果過程簡單,直接算出結果
,函數會被優化,但是oc方法不會;局部變量可以被優化 - 匯編里面方法調用,至少傳兩個參數:self,cmd(sel)
- 64位CPU由于寄存器多,函數調用時優先使用寄存器。但是,最多有6個寄存器放參數,多余的參數會放到棧空間
棧幀
- stack frame
- 函數調用時,sp與bp之間的空間;不是每一個函數都有棧幀的,比如x86函數優化時就沒有