美文网首页
8086汇编(17)call和ret

8086汇编(17)call和ret

作者: 迷心迷 | 来源:发表于2019-03-29 08:40 被阅读0次

call和ret指令

1、call标号

  • 将下一条指令的偏移地址入栈后
  • 转到标号处执行指令

2、 ret
将栈顶的值出栈,赋值给ip

3、 call和ret联合使用的作用其实是高级语言中的函数调用

4、 实践,考虑以下几种情况

  • 有无参数
  • 有无返回值
  • 现场保护
  • 局部变量
  • 堆栈平衡

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 

函数的返回值

assume cs:code, ds:data, ss:stack

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


; 数据段
data segment  
    a dw 0
    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 mathFunc3
    
    mov bx, ax  
    
    ; 退出
    mov ax, 4c00h
    int 21h 
    
; 返回2的3次方
; 返回值放到ax寄存器中     
mathFunc3:  
    mov ax, 2
    add ax, ax
    add ax, ax 
    
    ret 

; 返回2的3次方
; 返回值放到a中     
mathFunc2:  
    mov ax, 2
    add ax, ax
    add ax, ax 
    
    mov a, ax
    
    ret  
    
; 返回2的3次方
; 返回值放到ds:0中     
mathFunc1:  
    mov ax, 2
    add ax, ax
    add ax, ax 
    
    mov [0], ax
    
    ret 
                
code ends  

end start

函数的参数

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
    
    push 3333h
    push 3333h 
    call sum3
    add sp, 4
     
    mov cx, 1122h 
    mov dx, 2233h 
    call sum1 
    
    mov word ptr [0], 1122h 
    mov word ptr [2], 2233h 
    call sum2  
    
    ; 退出
    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

; 栈平衡:函数调用前后的栈顶指针要一致
; 栈如果不平衡的结果:栈空间迟早会被用完

递归调用

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 sum
    add sp, 4  
    
    push 1122h
    push 3344h  
    call minus   
    
    ; 退出
    mov ax, 4c00h
    int 21h 
    
; 返回值放ax寄存器
; 传递2个参数(放入栈中)    
sum:   
    ; 访问栈中的参数
    mov bp, sp
    mov ax, ss:[bp+2]
    add ax, ss:[bp+4]
    
    ret 
        
; 返回值放ax寄存器
; 传递2个参数(放入栈中)   
minus:
    mov bp, sp 
    mov ax, ss:[bp+2]
    sub ax, ss:[bp+4]
     
    ret 4
    
    
                
code ends  

end start

; 栈平衡:函数调用前后的栈顶指针要一致
; 栈如果不平衡的结果:栈空间迟早会被用完

; 栈平衡的方法
; 1.外平栈
;    push 1122h
;    push 3344h 
;    call sum
;    add sp, 4 
; 2.内平栈
;    ret 4

调用约定

  • __cdecl: 外平栈,参数从右至左入栈
  • __stdcall: 内平栈,参数从右至左入栈
  • __fastcall: 内平栈,ecx,edx分别传递前面两个参数,其他参数从右至左入栈
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 1111h
    push 2222h 
    push 3333h 
    call sum
    add sp, 6     
    
    ; 退出
    mov ax, 4c00h
    int 21h 
    
; 返回值放ax寄存器
; 传递2个参数(放入栈中)    
sum:   
    ; 访问栈中的参数
    mov bp, sp
    mov ax, ss:[bp+2]
    add ax, ss:[bp+4]
    add ax, ss:[bp+6]  
    
    ret  
                
code ends  

end start

; 函数调用的本质
; 1.参数:push 参数值
; 2.返回值:返回值存放到ax中
; 3.栈平衡

函数的局部变量

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 1
    push 2 
    call sum 
    add sp, 4 
     
    push 1
    push 2 
    call sum 
    add sp, 4   
    
    ; 退出
    mov ax, 4c00h
    int 21h 
    
; 返回值放ax寄存器
; 传递2个参数(放入栈中)    
sum:
    ; 保护bp    
    push bp
    ; 保存sp之前的值:指向bp以前的值
    mov bp, sp
    ; 预留10个字节的空间给局部变量 
    sub sp, 10  
    
    ; -------- 业务逻辑 - begin
    ; 定义2个局部变量
    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
    
    ; 访问栈中的参数
    mov ax, ss:[bp+4]
    add ax, ss:[bp+6] 
    add ax, ss:[bp-6] 
    ; -------- 业务逻辑 - end
                       
    ; 恢复sp
    mov sp, bp
    ; 恢复bp
    pop bp
    
    ret 
                
code ends  

end start

; 函数的调用流程(内存)
; 1.push 参数
; 2.push 函数的返回地址
; 3.push bp (保留bp之前的值,方便以后恢复)
; 4.mov bp, sp (保留sp之前的值,方便以后恢复)
; 5.sub sp,空间大小 (分配空间给局部变量)
; 6.执行业务逻辑
; 7.mov sp, bp (恢复sp之前的值)
; 8.pop bp (恢复bp之前的值)
; 9.ret (将函数的返回地址出栈,执行下一条指令)
; 10.恢复栈平衡 (add 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 1
    push 2 
    call sum 
    add sp, 4 
     
    push 1
    push 2 
    call sum 
    add sp, 4   
    
    ; 退出
    mov ax, 4c00h
    int 21h 
    
; 返回值放ax寄存器
; 传递2个参数(放入栈中)    
sum:
    ; 保护bp    
    push bp
    ; 保存sp之前的值:指向bp以前的值
    mov bp, sp
    ; 预留10个字节的空间给局部变量 
    sub sp, 10  
    
    ; -------- 业务逻辑 - begin
    ; 定义2个局部变量
    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
    
    ; 访问栈中的参数
    mov ax, ss:[bp+4]
    add ax, ss:[bp+6] 
    add ax, ss:[bp-6] 
    ; -------- 业务逻辑 - end
                       
    ; 恢复sp
    mov sp, bp
    ; 恢复bp
    pop bp
    
    ret 
                
code ends  

end start

; 函数的调用流程(内存)
; 1.push 参数
; 2.push 函数的返回地址
; 3.push bp (保留bp之前的值,方便以后恢复)
; 4.mov bp, sp (保留sp之前的值,方便以后恢复)
; 5.sub sp,空间大小 (分配空间给局部变量)
; 6.执行业务逻辑
; 7.mov sp, bp (恢复sp之前的值)
; 8.pop bp (恢复bp之前的值)
; 9.ret (将函数的返回地址出栈,执行下一条指令)
; 10.恢复栈平衡 (add 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 
    
    
    mov ax, 11
    mov bx, 11
    sub ax, bx
    
    ; 退出
    mov ax, 4c00h
    int 21h 
                
code ends  

end start

相关文章

  • 8086汇编(17)call和ret

    call和ret指令 1、call标号 将下一条指令的偏移地址入栈后 转到标号处执行指令 2、 ret将栈顶的值出...

  • 汇编-8086 栈平衡,call和ret使用

    先上代码 开始分析 将在数据段中的字符串Hello!的位置push到栈中($:代表结束,offset在数据段的偏移...

  • 汇编- call和ret

    尽管这两条指令看起来很简单,但是很多初学者并不能完全领会这两条指令的本质。所以我把它们作为一个单独的章节来介绍,我...

  • 【8086汇编】-- call 和 ret 指令 的应用和本质

    在高级语言开发中会把一些功能封装成方法然后调用,下面我们来用汇编实现一个打印hello world的方法 先实现打...

  • 8086汇编(25)ret和retf

    ret和retf ret指令用栈中的数据,修改IP的内容,从而实现近转移; retf指令用栈中的数据,修改CS和I...

  • 汇编语言知多少(三): 函数调用

    接着上一篇文章, 这篇主要讲汇编程序中函数的调用. call 和 ret 指令: 函数的调用. call 标号 :...

  • 汇编学习笔记(四)

    call和ret指令 call和ret都是转移指令,都修改IP,或同时修改CS和IP。 ret和retf ret ...

  • 汇编分析&编译器优化

    汇编的种类 8086汇编(8086处理器是16bit的CPU) Win32汇编 Win64汇编 ARM汇编(嵌入式...

  • 逆向 - arm64汇编 - 第一天

    1. 汇编语言种类 8086汇编(8086处理器是16bit的CPU)Win32汇编Win64汇编ARM汇编(嵌入...

  • 1.汇编初识

    汇编语言常见种类: 8086汇编 (8086处理器是16bit的CPU) Win32汇编 Win64汇编 AT&T...

网友评论

      本文标题:8086汇编(17)call和ret

      本文链接:https://www.haomeiwen.com/subject/twjkbqtx.html