• CALL和RET指令


    CALL和RET指令

    call和ret属于转移指令,都修改IP或者CS,IP。进程用来设计子程序,也就是函数

    ret和retf

    ret指令用栈中的数据来修改IP,实现近转移

    retf指令用栈中的数据来修改cs和ip,实现远跳转

    ret

    在汇编中执行ret的指令时,需要进行两步操作

    (ip)=((ss)*16+(sp))

    (sp)=(sp+2)

    意思就是把当前栈的东西送给ip,然后再栈顶指针下移,相当于就是pop ip

    retf

    执行retf指令时分为四步操作:

    1 (ip)=((ss)*16+(sp))

    2 (sp)=(sp)+2

    3 (CS)=((ss)*16+(sp))

    4 (sp)=(sp)+2

    相当于:

    pop ip

    pop cs

    例:

    assume cs:code,ss:stack

    stack segment
    db 16 dup (0)
    stack ends

    code segment
    mov ax,4c00h
    int 21h

    start:
    mov ax,stack
    mov ss,ax
    mov sp,16
    ;init stack

    mov ax,0
    push ax
    mov bx,0
    ret
    code ends

    end start

    这个程序表示的意思就是ret执行后,cs:ip跳转到第一条指令来执行

    assume cs:code,ss:stack

    stack segment
    db 16 dup (0)
    stack ends

    code segment
    mov ax,4c00h
    int 21h

    start:
    mov ax,stack
    mov ss,ax
    mov sp,16
    ; init stack

    mov ax,0
    push cs
    push ax
    mov bx,0
    retf
    code ends

    end start

    执行retf后,回到了第一条指令

     

    实现从内存1000:0000开始执行指令

    stack segment
    db 16 dup (0)
    stack ends

    code segment
    assume cs:code,ss:stack
    start:
    mov ax,stack
    mov ss,ax
    mov sp,16
    ;init stack
    mov ax,1000h
    push ax
    mov ax,0000h
    push ax
    retf
    code ends

    end start

    CALL指令

    CPU执行call指令时要进行两步操作

    1 将当前的ip或者cs:ip入栈

    2 转移

    call指令不能断跳转,除此之外call指针实现转移的原理和jmp相同

    依据位移进程转移的call指令

    call标号(将当前的IP压栈后跳转到标号)

    CPU执行CALL指令后进行的操作:

    (sp)=(sp)-2

    ((ss)*16+(sp))=(ip)

    (ip)=(ip)+16位位移

    相当于进行了

    push ip

    jmp near ptr 标号

    call标号

    16位位移=“标号”最小的地址-call指令后的第一个字节的地址

    16位范围

    -32768~32767

    例:

    1000:0  mov ax,0
    1000:3 call s
    1000:6 inc ax
    1000:7s: pop ax

    这个程序执行后ax等于6

    转移的目的地址在指令中的call指令

    call far ptr 标号实现的是段间转移

    CPU执行此种格式的call指令时,执行以下操作:

    (sp)=(sp)-2

    ((ss)*16+(sp))=(cs)

    (sp)=(sp)-2

    ((ss)*16+(sp))=(IP)

    (CS)=标号的段地址

    (IP)=标号的便宜偏移地址

    执行call far ptr标号就相当于

    push CS

    push IP

    jmp far ptr标号

    例:

    1000:0  mov ax,0
    1000:3 call far ptr s
    1000:8 inc ax
    1000:9s:
    pop ax
    add ax,ax
    pop bx
    add ax,bx

    执行完之后 ax=10h bx=1010h

    转移地址在寄存器中的call指令

    格式:call reg16

    功能:

    (sp)=(sp)-2

    ((ss)*16+(sp))=(ip)

    (ip)=reg16

    用汇编来描述就是

    push IP

    jmp reg16

    例:

    1000:0  mov ax,6    ;ax=6
    1000:3 call ax
    1000:5 inc ax
    1000:6 mov bp,sp ;跳转到这里ip=5
    ;相当于push 5
    add ax,[bp] ;6+5=11

    ax=0bh

    转移地址在内存中的call指令

    转移地址在内存中有两种格式:

    第一种格式

    1 call word ptr 内存单元地址

    用汇编来解释就是

    push IP

    jmp word ptr 内存单元地址

    ;例
    mov sp,10h
    mov ax,0123h
    mov ds:[0],ax
    call word ptr ds:[0]

    执行后(IP)=0123h,(sp)=0Eh

    第二种格式

    call dword ptr

    相当于执行

    push CS

    push IP

    jmp dword ptr 内存单元地址

    CS

    ;例
    mov sp,10h
    mov ax,0123h
    mov ds:[0],ax
    mov word ptr ds:[2],0
    call dword ptr ds:[0]

    (cs)=0,(IP)=0123h,(sp)=0CH

    CS在高位,IP在低位

    stack segment
    dw 8 dup (0)
    stack ends

    code segment
    assume cs:code,ss:stack
    start:
    mov ax,stack
    mov ss,ax
    mov sp,16
    ;init stack
    mov ds,ax
    mov ax,0
    call word ptr ds:[0EH] ;跳转到栈顶修改IP的值
    ;push ip=inc ax的地址
    inc ax
    inc ax
    inc ax

    mov ax,4c00h
    int 21h

    code ends

    end start

    call和ret的配合使用

    分析第一个简单程序

    code segment
    assume cs:code
    start:
    mov ax,1
    mov cx,3 ;表示循环3次

    call s

    mov bx,ax ;bx=8
    mov ax,4c00h
    int 21h

    s: add ax,ax
    loop s
    ret ;返回时ax=8

    code ends

    end start

    分析第二个程序

    assume cs:code

    stack segment
    db 8 dup (0)
    db 8 dup (0)
    stack ends

    code segment

    start:
    mov ax,stack
    mov ss,ax
    mov sp,16
    ;init stack

    mov ax,1000
    call s

    mov ax,4c00h
    int 21h

    s:
    add ax,ax
    ret
    code ends
    end start

    其实就和设计函数差不多

    模块化程序设计

    利用call和ret来进行各种函数子进程的编写来达成模块化的程序设计

    参数和结果传递的问题

    通常利用寄存器和栈来存储函数的各种内容,比如参数,返回值等等

     

  • 相关阅读:
    sass学习笔记1
    javascript 数组的深度复制
    div+css定位position详解
    滚动加载图片(懒加载)实现原理
    移动端布局经验
    js 扁平化输出数组
    axiso基本使用及python接收处理
    JSP内置对象
    JSP基本语法
    tomcat环境搭建
  • 原文地址:https://www.cnblogs.com/beautiful7/p/14269367.html
Copyright © 2020-2023  润新知