5.call和ret指令

weixin_33670713發表於2018-08-02
1751468-f0595404a2e609cf.png
1751468-b73d6d73163501bc.png
螢幕快照 2018-08-02 10.57.29.png

call和ret指令使用:
assume cs:code, ds:data, ss:stack

; 棧段
stack segment
    db 100 dup(0)
stack ends  


; 資料段
data segment 
    db 100 dup(0) 
    string db 'Hello!$'
data ends


; 程式碼段
code segment
start:
    ; 手動設定ds、ss的值
    mov ax, data
    mov ds, ax
    mov ax, stack
    mov ss, ax  
    
    ; 業務邏輯 
    call print
    
    mov ax, 1122h
    mov bx, 3344h
    add ax, bx  
    
    ; 退出
    mov ax, 4c00h
    int 21h 
    
; 列印字串    
print:    

    ; ds:dx告知字串地址    
    mov dx, offset string
    mov ah, 9h
    int 21h
    
    ret 
                
code ends  

end start 

; 函式的要素
; 1.引數
; 2.返回值
; 3.區域性變數

實現函式返回值:

demo1:使用ds

assume cs:code ,ds:data ss:stack
data segment
  db 100 dup(0)
data ends

code segment
start:
      mov ax,data
      mov ds,ax
      call  returnFunc
      mov bx,[0]

returnFunc :
      mov ax,2
      add ax,ax
      mov [0],ax
      ret
code ends
end start

demo2:使用ds中的別名

...
data segment
   ;定義別名result
   result dw 0
data ends
...
start:
      mov ax,data
      mov ds,ax
      call  returnFunc
      mov bx,result
...
returnFunc :
      mov ax,2
      add ax,ax
      mov result,ax
      ret

demo3:通用做法是返回值直接放在ax通用暫存器中


實現函式傳參:

1.使用ax暫存器儲存引數來實現傳遞
2.使用棧來儲存引數來傳遞,也是通用做法:

  • 使用bp來快速訪問棧中資料
  • 使用mov sp指令來快速釋放棧中資料
assume cs:code, ds:data, ss:stack

; 棧段
stack segment
    db 100 dup(0)
stack ends  

; 資料段
data segment  
    db 100 dup(0) 
data ends

; 程式碼段
code segment
start:
    ; 手動設定ds、ss的值
    mov ax, data
    mov ds, ax
    mov ax, stack
    mov ss, ax  
    
    ; 業務邏輯
    push 1122h
    push 3344h 
    call sum3 
    add sp, 4
    
    push 2222h
    push 2222h 
    call sum3
    add sp, 4
        
    ; 退出
    mov ax, 4c00h
    int 21h 
    
; 返回值放ax暫存器
; 傳遞2個引數(放入棧中)    
sum3:   
    ; 訪問棧中的引數
    mov bp, sp
    mov ax, ss:[bp+2]
    add ax, ss:[bp+4]
    ret 
          
; 返回值放ax暫存器
; 傳遞2個引數(分別放ds:0、ds:2)    
sum2:         
    mov ax, [0]
    add ax, [2]
    ret 
            
; 返回值放ax暫存器
; 傳遞2個引數(分別放cx、dx中)    
sum1:  
    mov ax, cx
    add ax, dx
    ret 
                
code ends  
end start
; 棧平衡:函式呼叫前後的棧頂指標要一致
; 棧如果不平衡的結果:棧空間遲早會被用完

注意區分遞迴呼叫、函式內呼叫函式和連續呼叫多個函式對棧的使用的區別,
函式內呼叫函式會一直往棧中壓資料,而多函式連續呼叫,只會當前函式棧中資料釋放後再繼續下一個函式的壓棧操作。


棧平衡的方法:

1.外平棧,函式外面進行平棧,也就是上面的操作,要是常用的做法
2.內平棧,函式內進行平棧,函式內呼叫其他函式的時候:

sum2:         
    mov ax, [0]
    add ax, [2]
    call sum1
    ret 
 
sum1:  
    mov ax, cx
    add ax, dx
    ret 4

相關文章