zoukankan      html  css  js  c++  java
  • 汇编语言基础之二 各种寻址和过程进出简介

    指令标记法

    Prefix Instruction [operand 1], [operand 2] ; comment

    注意,不能让内存同时作为目的操作数和源操作数。

    操作数

    一般指令的操作数可以有0~2个。

    隐式操作数- Implicit Operands

    隐式操作数是由指令本身指定的。CLI和STI就是这样的不需要指出操作数的指令。CLI和STI指令设置和清除在EFlags寄存器中的中断标志位。CLI和STI永远只操作那个bit位。

     

    寄存器寻址- Register Operands

    也就是指令使用寄存器中的值作为源或目的操作数。

    CALL    EDI              ; EDI contains address to call

    MOV     EAX, EBX     ; EAX<-EBX EAX = destination EBX = source

    INC      EAX             ; EAX=EAX+1 – EAX=source and destination

    立即数- Immediate Operands

    立即数是指令的一部分,直接指定了操作数的值。立即数允许用户设置一个常量到变量中,或者引用一个固定的内存地址。

    MOV     EAX,177      ; load EAX with 177

    MOV     CL,0FFH      ; load CL with 255

    CALL    12341234H ; call routine at location 12341234H

    IO操作数- I/O Operands

    IO操作数不在用户态模式程序中使用。IO指令被用来引用IO map中的设备。这些包括绝大多数的硬件设备比如PICS,串行口,并行口,磁盘控制器等等。

    IN       AL, 04H    ; read port location 4 into AL register

    OUT    04H, AL    ; write AL register to port location 4

    内存引用操作数

    内存引用操作数是指通过许多种内存寻址方式来获取操作数的值的方式。

    1. 绝对寻址- Direct Addressing

    指的是地址本身用作操作数。这被用来指出程序占用的固定地址,比如说实例的全局变量。

    MOV      AL, [12341234H]

    INC       DWORD PTR [12341234H]

     

    2. 间接寻址- Based Addressing

    指使用寄存器来存放地址来作为操作数的方式。这经常被用来解析指针所指向的变量。

    MOV      AL,[ECX]

    DEC      DWORD PTR [ESI]

     

    3. 带有偏移量的间接寻址- Base Plus Displacement Addressing

    跟间接寻址差不多,不同之处就是要在寄存器的地址上加上一个额外的偏移量。这种方法用来访问一个结构之中的变量。寄存器中的指针指向这个结构的起始地址,位移能够允许引用到正确的结构元素。这种方式比不得不用指针直接指向每一个要被访问的元素好,因为经常出现一段代码中访问一个结构体的多个元素的情况。这样,寄存器中的指针值只需设置一次,只有偏移量改改就好了。

    LEA    EDX,[ESP+0x4]

    MOV   ECX, [EBP-0x10]

     

    4. 基址+偏移量寻址- Index Plus Displacement Addressing

    这种寻址方式与带偏移量的间接寻址一样,区别就是寄存器与固定的偏移量的角色互换了。现在基址是固定的位置,加上一个在寄存器中的偏移量。这种方式主要用于访问静态内存中的数组中的元素。

    MOV     EAX,1234124H[ESI]

     

    5. 变址寻址- Base Plus Displacement Plus Index Addressing

    这是由多种寻址方式混合成的寻址方式。它综合了前面的两种方式。用来访问声明在栈上或者动态分配在堆上的地址。寄存器指向基址,另一个寄存器保存偏移量,还有一个固定的偏移量可以被包含进来。

    MOV EAX,[EBP+8][ESI]

    INC WORD PTR [EBX+EAX*2]

     

     

    过程调用的进入和退出

    在进入和离开一个程序的时候,代表性的栈框架(stack frame)会被建立,从而使程序能够方便的访问参数和局部变量。Intel处理器使用EBP和ESP两个寄存器来完成这项工作。下面的信息就show出了调用子函数的时候,一个栈框架是如何建立的例子。

    过程调用部分

    MOV    EAX, Argument 1  ; load EAX with value of Argument 1

    PUSH  EAX                      ; push first argument onto stack

    CALL   sub1

    在调用函数之前,参数被压栈。分解PUSH指令,它做了下面的事情:

    ESP <- ESP – 4 ; decrement stack pointer

    SS:[ESP] <- operand ; load operand into location pointed to by ESP

    分解CALL指令,下面是call的指令:

    PUSH EIP                     ; push return address on stack

    EIP <- destination       ; EIP set to first instruction on the sub1 routine

    这时栈看起来应该是这样子的:

    ????

       

    EIP(也就是返回值)

    <-

    ESP

    Argument 1

       

    ????

       

     

    过程入口部分

    典型的过程入口看起来应该是这样子的:

    PUSH    EBP          ; save the base pointer

    MOV     EBP,ESP    ; setup new stack frame

    SUB      ESP,24      ; allocate local variables

    发生了三件事,第一,我们保存了EBP寄存器的值;多数的编译器假设EBP寄存器不会被调用的过程破坏。第二,我们建立了栈框架,工作拷贝ESP到EBP寄存器,我们为过程做到了这一点。第三,我们为局部变量创造了空间,这些空间是分配在栈上的。现在栈看上去应该是这样的:

         

    ????

       

    Local Var n

    <-

    ESP

         
         
         

    Local Var 1

       

    Saved EBP

    <-

    EBP

    EIP(返回值)

       

    Argument 1

       

    ????

       

     

    访问参数和局部变量

    要访问参数,可以在过程的任何地方使用如下的指令:

    MOV    EAX,[EBP+8]    ; read argument one into EAX register

    要访问局部变量,使用如下的指令即可:

    MOV    EAX,[EBP-4]     ; read first local variable

     

    过程退出

    典型的退出部分看起来像下面这样:

    MOV    ESP,EBP  ; restore stack pointer

    POP    EBP          ; restore base pointer

    RET     4              ; return

    退出一个过程先要恢复ESP,恢复的过程是把它设置成为与EBP的值相同即可。然后恢复EBP到它刚刚进入这个过程调用时的样子,该值被早些时候压入了栈中。最后的指令是RET,分析RET指令如下:

    EIP <- POP() ; reset our instruction pointer

    ESP <- ESP + count ; fixup stack for arguments

  • 相关阅读:
    day 28 客户端服务端架构介绍,互联网协议,互联网协议补充,三次握手与四次挥手
    day25 单例模式实现方法一 单例模式实现方法二
    day24 反射/定制__str__方法控制对象的打印格式/定制__del__方法回收系统资源/元类介绍以及默认元类type创造类的过程/自定义元类控制类的创建过程/自定义元类控制类的调用过程
    day 23 封装之如何隐藏、封装之隐藏属性的底层原理、封装的真正意义、property特性、绑定方法与非绑定方法
    day22 组合、菱形继承问题、C3算法与mro介绍、在子类派生的新方法中重用父类功能的两种方式、super()严格以来继承关系、多态与鸭子类型
    day21 对象定制自己独有的属性/属性查找/绑定方法/小结/继承介绍/继承与派生
    day19 正泽表达式,sys模块,打印进度条,subprocess模块
    day18 logging模块的补充/jason序列化与反序列化/json补充/pickle序列化与反序列化/time模块/datetime模块/random模块/os模块
    day17 包的使用 logging模块的基本用法
    day16 面向过程编程/模块介绍/import导入模块/ from...import导入模块/循环导入问题/模块的搜索路径/区分python文件的两种用途/软件开发的目录规范
  • 原文地址:https://www.cnblogs.com/awpatp/p/1593259.html
Copyright © 2011-2022 走看看