zoukankan      html  css  js  c++  java
  • 汇编语言-子程序调用

    汇编语言-子程序调用

    ret与ref指令

    ret

    ret == pop IP

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

    功能介绍

    retf指令用栈中的数据,修改CS和IP的内容,从而实现远转移
    CPU执行ret指令时,进行下面两步操作:

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

    相当于进行:

    pop IP

    retf

    retf == pop IP + POP CS

    功能介绍

    CPU执行retf指令时,进行下面两步操作:

    (1)(IP) = ((ss) * 16 + (sp))
    (2)(sp) = (sp) + 2
    (3)(CS) = ((ss) * 16 + (sp))
    (4)(sp) = (sp) + 2

    相当于进行:

    pop IP
    pop CS

    call指令

    call 标号

    功能介绍

    (把当前IP压栈后, 转到标号处执行指令)

    a. (SP) = (SP) - 2
       ((SS) * 16 + SP) = (IP)
    b. (IP) = (IP) + 16位位移

    相当于:

    push IP
    jmp near ptr 标号
    • 16位位移 = “标号”处的地址 - call指令后的第一个字节的地址;
    • 16位位移的范围 -32768—-32767, 用补码表示;
    • 16位位移由编译程序在编译时算出;

    call far ptr 标号

    功能介绍

    (把当前CS,IP压栈后, 转到标号处执行指令)

    a. (SP) = (SP) - 2
       ((SS) * 16 + SP) = (CS)
    b. (SP) = (SP) - 2
       ((SS) * 16 + SP) = (IP)
    c. (CS) = 标号所在段的段地址
       (IP) = 标号在段中的偏移地址

    相当于:

    push CS
    push IP
    jmp par ptr 标号

    call 16位寄存器

    功能介绍

    (sp) = (sp) – 2
    ((ss) * 16 + (sp)) = (IP)
    (IP) = (16位寄存器) 

    相当于:

    push IP 
    jmp 16位寄存器

    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 内存单元地址

    实例展示

    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
    ((IP)= ds:[0], (CS) = ds:[2])

    子程序调用

    通过上面介绍的两个指令,我们可以完成子程序的调用。简单调用程序如下:

    assume cs:code
    
    code segment
    start:  mov ax,1
        mov cx,3
        call s
    
        mov bx, ax
        mov ax,4c00H
        int 21H
    
        s:  add ax,ax
            loop s
        ret
    
    code ends
    end start

    子程序调用-传递参数问题

    我们在写c语言或者其他高级语言的时候,要经常用到函数之间的参数传递这一个概念。那么在汇编语言中,我们怎么做到总程序和子程序之间的参数传递呢?

    寄存器存放法

    首先可以考虑在寄存器中,存放数据,比如a存放在ax中,b存放在bx中。

    mov ax,a
    mov bx,b

    这种方式可以在参数比较少的时候使用,但是参数多了呢?那么那么多的寄存器给你存放。因此这种方式不是长久之计。

    内存存放法

    我们想到了一个比较好的思路,就是将参数保存到内存中,然后在寄存器中存放这些参数的首地址,通过首地址访问一系列的参数。这种方式,显然可以存放更多的数据,并且没有数量上的限制。

    ;参数存放段
    data segment
        db 'aaaaa',0
        db 'aaaaa',0
        db 'aaaaa',0
    data ends
    
    code segment 
    
        ...
        ...
        mov ax,data
        mov es,ax
        mov si,0
    
        call sub1
    
        ...
        ...
        sub1:   mov ax,es[si]
                ...
                ...
        ret
    
    code ends

    这里还是存在一个问题,如果在主程序中用到了一个xx寄存器,然后在子程序中也用到了这个xx寄存器,那么当子程序返回到主程序的时,主程序中存放参数的内存地址已经没有记录了,程序出错。

    内存存放法(改进)

    为了解决这个问题,我们需要每次进入子程序时,将子程序中的需要用到的寄存器,push到栈中,每次退出子程序时,将相应寄存器pop出来。

    子程序都应遵循下面的模式:

    capital:
            push cx
            push si
    
    change:
            mov cl,[si]
            mov ch,0
            jcxz ok
            and byte ptr[si],11011111B
            inc si
            jmp short change
    
    ok: 
            pop si
            pop cx
            ret
  • 相关阅读:
    ArrayList removeRange方法分析
    LinkedHashMap源码分析(基于JDK1.6)
    LinkedList原码分析(基于JDK1.6)
    TreeMap源码分析——深入分析(基于JDK1.6)
    51NOD 2072 装箱问题 背包问题 01 背包 DP 动态规划
    51 NOD 1049 最大子段和 动态规划 模板 板子 DP
    51NOD 1006 最长公共子序列 Lcs 动态规划 DP 模板题 板子
    8月20日 训练日记
    CodeForces
    CodeForces
  • 原文地址:https://www.cnblogs.com/AbeDay/p/5026848.html
Copyright © 2011-2022 走看看