zoukankan      html  css  js  c++  java
  • NASM手册阅读笔记(7)

    简述

      这一些预处理指令是为了方便我们使用堆栈传参的时候的程序调用的。
      我们一般的调用过程如下
      proc1:
          push   参数1        ;  参数1 压栈
          push   参数2        ;参数2   压栈
          push  参数3         ;参数2   压栈
          call     proc2
     
      proc2:
           push bp          ; bp内容压栈, 为的是保存bp寄存器的原始值
           mov  bp,sp           ; 将SP 内容 保存到 bp 中, 之后再结束前bp的值都不应该再发生改变
           sub   sp, ?            ; 减少 sp的指向,相当于预先开辟一篇空间 给我们的临时变量使用
           mov   ax, [bp + 2+ 2]           ; 假设之前参数3 是2 字节,那么这就是获取参数3 的内容,注意bp寄存器实际指向的是存储BP寄存器原始内容的地方,+2 后指向call压栈的放回地址 再+2 才是压栈的最后一个参数内容
           mov   [bp - 2 ],ax      ; 假设我们的临时变量的大小是2字节,那么这就是取我们
           XXXXXXXXXXX
           mov  sp, bp
           pop bp
           ret
     
      那么接下来要介绍的预处理指令就是为了方便这个过程的
      注意一点: 接下来用到的指令内容辉县一些信息保存到上下文栈中,所以接下来的指令都是要配合上下文栈来使用的
      

    %stacksize

    格式

    %stacksize flat
    %stacksize flat64
    %stacksize large
    %stacksize small

    说明

    从上面的简述中可知,堆栈中的变量是通过bp寄存器作为基址来进行寻址的,那么这条指令就是告诉预处理器,我们到底用 BP 还是 EBP 还是RBP来寻址
    flat64       指定使用 RBP 来进行栈的寻址
    flat             指定使用 EBP 来进行栈的寻址
    large          指定使用 BP 来进行栈的寻址
    small         指定使用 BP 来进行栈的寻址,它会认为BP之前已经压栈,所以其他的是会自动将BP压栈一次吗?

    %arg

    格式

    %arg param1:word, param2:type

    说明

    这个是定义其他函数传递过来的参数 参数名:参数类型 以逗号分隔
    之后就可以直接直接使用定义的名称寻址
    mov  ax, [param1]    =>          mov ax,[bp+4]
    mov  ax, [param2]    =>          mov ax,[bp+6]
    所以汇编器就会根据变量的类型以及 %stacksize 设置的寄存器将 param1 形式的参数自动替换为 bp+x形式的参数

    %local

    格式

    %local param1:word, param2:type

    说明

    与 %arg 是同理的,只不过他计算的是本地变量也就是
    %arg   计算的是 bp + ? 的形式
    %local 计算的是 bp - ? 的形式
    所以这里要注意一点,%arg的变量使用的时候内存是已经开辟并赋值好了的,这是调用它的函数负责的
    而%local定义的变量是需要本函数自己去开辟空间的,即使用 sub sp, xxx 这样子的形式去开辟空间
     

    补充说明

    A. 如下表格是一个堆栈的展示,主要用于说明 %arg 和%local 定义变量的对应增长方向以及对应关系,注意堆栈是从高地址往低地址方向增长的
     
    1   local2
    2   local1
    3   bp寄存器内容
    4   call压栈的返回地址
    5   arg1
    6   arg2
        
      B. ENTER / LEAVE    
    enter
        等于 push ebp和mov ebp,esp
        先将ebp保存到对账中,然后将esp保存到ebp中
     
    Leave
        等于mov esp,ebp和pop ebp
        将保存在ebp中的内容还给 esp 并回复ebp原来的值
     
    这是一般出现下一个函数开始的和结尾处的指令
    只用时保持堆栈的平衡,因为函数开始的时候的堆栈保存在了ebp中,所以如果这个函数里面有堆栈不平和的情况,使用leave 指令的时候总能还原进来的时候的堆栈指针。当然前提是不能修改ebp的值

    enter 可以跟参数

    enter numbytes, nestinglevel
    numbytes 表示为当前堆栈 保留多少 字节,自动对齐4 相当于指令 sub esp, numbytes
    而 nestinglevel 词法嵌套级,没明白啥意思 填 0 
        
     
    C. 例子
    silly_swap:                  
    %push mycontext             ; 之前说过有信息要使用上下文栈 所以这一先压栈一个上下文   
    %stacksize small              ; 设置使用bp寄存器来寻址        
    %assign %$localsize 0     ; 这里定义了一个上下文栈的本地宏   
    %local old_ax:word, old_dx:word             ; 这就是定义了本地参数          
            enter   %$localsize,0   ;  保存bp,赋值 sp, 开辟空间              
            mov     [old_ax],ax     ;  存值               
            mov     [old_dx],dx     ;  存值          
            mov     ax,bx               
            mov     dx,cx               
            mov     bx,[old_ax]     ;  取值           
            mov     cx,[old_dx]     ;  取值         
            leave                   ; enter 返现操作             
            ret                     ;                   
    %pop                        ; 销毁 之前创建的 mycontext 上下文堆栈,这样就不会对别的内容产生影响
  • 相关阅读:
    java格式化sql
    Java 实现对Sql语句解析
    java 解析四则混合运算表达式并计算结果
    SQL转Java代码小工具
    eclipse导入maven工程步骤
    xml文件的schema也是经过jdk编译器编译的,如果xsd没引入完整,而xml中又用到了这些标签,就会编译不通过啊。
    eclipse bug之'<>'operator is not allowed for source level below 1.7
    eclipse默认指定项目的编译器版本
    eclipse导入maven项目后依赖jar包更新问题->update project按钮
    maven也是apache下的项目
  • 原文地址:https://www.cnblogs.com/alwaysking/p/12287451.html
Copyright © 2011-2022 走看看