美文网首页
【8086汇编】-- call 和 ret 指令 的应用和本质

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

作者: fanglaoda | 来源:发表于2018-10-07 15:20 被阅读0次

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

    先实现打印的功能

    assume cs:code    ds:data   ;assume是伪指令 作用是申明本程序中cs为code ds为data
    
    
    data segment                ;segment .... ends 定义一个段
    
       string db 'Hello World!$'  
        
    data ends
    
    
    code segment 
        
    start:                      ;start 伪指令地址的标号
    
          
          mov ax, data
          mov ds, ax
              
           ;ds + dx 才能给打印函数传参
          mov dx,offset string
          
          ;当ah == 9h 的时候 调用系统的print函数 
          mov ah,9h  
          int 21h    
           
          ;当ah == 4ch 的时候 调用系统的退出函数
          mov ax, 4c00h
          int 21h
    
          
    code ends
    
    end start
    

    发现是正常输出的

    15373275595442.jpg

    如果想把打印封装成一个函数,在汇编里面通过callret指令配合使用的

    assume cs:code    ds:data    ss:stack
       
    
    stack segment
           db 10 dup(0) ;申请10个字节,并且默认都是0 
    stack ends       
    
    data segment
    
       string db 'Hello World!$'  
        
    data ends
    
    
    
    code segment 
        
    start:
          
          mov ax, data
          mov ds, ax 
          
          mov ax , stack
          mov ss ,ax
          mov sp , 10h
          
          call printFunc    
                          
          mov ax , 1122h                
          ;当ah == 4ch 的时候 调用系统的退出函数
          mov ax, 4c00h
          int 21h
    
    printFunc: ; printFunc为伪指令,值为下面一行的地址
          
          ;ds + dx 才能给打印函数传参
          mov dx,offset string
          
          ;当ah == 9h 的时候 调用系统的print函数 
          mov ah,9h  
          int 21h    
                 
           ret      
          
    code ends
    
    end start
    
    

    通过callret指令就可以实现一个方法调用了,相信你已经发现了下面的代码增加了一个stack段,这就涉及到callret指令的本质了

    callret指令的本质

    call指令,相当于

    1. push IP // 具体应该说是call下面一行的ip
    2. jmp 标号处

    ret指令,相当于

    pop IP

    call指令

    我们来查看程序执行过程来证明下

    点击下图执行代码

    15373376970904.jpg

    先来看看call代码的下一行的对应的cs:ip是多少,看下图

    15373385706754.jpg

    标号printFunc的cs:ip如图

    15373387353222.jpg

    由上图可以知道30那行代码的cs:ip为0712:0010,看下此时栈的内容

    15373382064902.jpg

    由于代码还没到那行,此时的栈为空栈所以此时的sp000A,当代码执行到call printFunc时,之前说到call指令,那么过了28行代码应该有入栈操作

    15373384702103.jpg

    我们发现了2个事情:

    1. 确实将30行的ip == 0010 入栈了;
    2. 代码通过cs:ip即 0712:0018 确实到了标号处

    从而验证了call指令的正确性

    ret指令

    还是上面的代码当执行到ret指令时

    15373390067711.jpg

    此时的cs:ip为0712:001F,安照对ret指令的描述,那么此时应该是出栈操作并赋值给ip,我们过掉44行,发现代码执行到该行,如图

    15373391951998.jpg

    和我们猜想的一样,再看看此时栈中的情况

    15373392362966.jpg

    发现栈定的指针已经+2了,这也符合我们的逾期,至此,已经证明了ret指令的结论

    自己实现函数调用

    既然我们清楚了callret的本质,我们是可以不使用这2个指令也可以实现函数调用和返回的修改代码如下

    assume cs:code    ds:data    ss:stack
       
    
    stack segment
           db 10 dup(0)
    stack ends       
    
    data segment
    
       string db 'Hello World!$'  
        
    data ends
    
    
    
    code segment 
        
    start:
          
          mov ax, data
          mov ds, ax 
          
          mov ax , stack
          mov ss ,ax
          
          mov sp , 10
          
          ;call printFunc
          push    0011h
          jmp    printFunc
                          
          mov ax , 1122h                
          ;当ah == 4ch 的时候 调用系统的退出函数
          mov ax, 4c00h
          int 21h
    
    printFunc: ; printFunc为伪指令,值为下面一行的地址
          
          ;ds + dx 才能给打印函数传参
          mov dx,offset string
          
          ;当ah == 9h 的时候统的print函数  调用系
          mov ah,9h  
          int 21h    
                 
           ;ret
           pop ax
           jmp ax      
          
    code ends
    
    end start
    
    

    我将call printFunc换成了

     push    0011h // 0011h是 mov ax , 1122h 的ip
    jmp    printFunc
          
    

    ret换成了

     pop ax
     jmp ax  
    

    同样实现了函数调用和返回

    相关文章

      网友评论

          本文标题:【8086汇编】-- call 和 ret 指令 的应用和本质

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