zoukankan      html  css  js  c++  java
  • Delphi汇编学习心得(不得闲) good

    把以下4个前提搞清楚以后,学习和使用汇编才有意义:

    --------------------------------------------------------------------------------------

    前提1:寄存器说明:
    EAX,EBX,EDX,ECX 通用寄存器,由程序员自己指定用途,也有一些不成文的用法:
    EAX:常用于运算。
    EBX:常用于地址索引。
    ECX:常用于计数。
    EDX:常用于数据传递。
    EIP 指令寄存器,指出当前指令所在的地址。
    ESP 栈指针,指向当前线程的栈顶(问题:是不是每个函数都有自己的栈,那每个线程都有一个栈是什么意思呢)
    EBP 栈基址指针,对调试起着很重要的作用(Base)。
    EDI,ESI 没有规定作什么用,一般用在源指针和目标指针的操作

    前提2:Register-Delphi默认模式
    参数传递模式...前三个数据.eax,edx,ecx...超过三个参数部分.放在堆栈传递
    头三个不大于4个字节(DWORD)的参数从左到右的传入EAX,EDX,ECX寄存器;接下去的参数按从左到右压栈。函数自己恢复堆栈。
    浮点数总压栈,不管它所占的字节是多少。
    对象方法总是有一个Self隐含参数,这个参数在所有的参数前面,即总是传给EAX(所以对于对象方法,程序员看到的第一个参数在EDX里)

    前提3:EBP基址指针的作用
    EBP是基址指针寄存器:一般用来确认堆栈帧的起始位置,也就是指向栈底。也就是说,一般一个函数入口的地址也就存放在EBP中(所以一般在进入函数的时候将ebp寄存器内容压栈,即保存其函数的上级调用函数的栈基地址,以便于以后返回调用)。

    前提4:查看汇编代码
    可以使用Ctrl+Alt+C打开Cpu View的Cpu调试窗口看里面的汇编代码。

    --------------------------------------------------------------------------------------

    1. 对栈的研究
    栈是向下增长的,即每压一次栈,栈顶的地址就减少一次,也可以说ESP的值就减小一次
    栈是线程相关的,每一个线程都拥有一个栈。
    程序利用ESP可以很灵活地访问栈,不一定要执行PUSH和POP栈顶才会改变,直接操作ESP也可以改变栈顶,也就是说ESP决定了栈顶的值。栈是有最大值的,通过编程环境可以设置,超出最大值就会发生栈溢出。

    看一个简单的例子,下面的指令是一条压栈指令,意思是将EAX的值压入栈中:
    PUSH EAX
    根据上面的性质,这条指令等价于下面的指令:
    SUB ESP, 4
    MOV ESP, EAX
    Cliff:所谓的向下生长,就是下面的地址小(比如0x00000000),上面的地址大(比如FFFFFFFF)。分配栈的起始地址任意,但压栈的话,地址向下移动,地址值变小(就是在海平面压一块海绵下去,放一块海绵,地址就下降一些)。但是对于单个栈而言,栈就1M或者2M大小,在这个区间内怎么折腾都行,但不能任意扩大。但整个程序的运行,内存分配不见得是向下生长的,这里仅仅是栈。其实很简单,使用Delphi任意执行一条push语句,观察一下ESP值的变化就行了。

    2. 函数如何被调用
    其实很简单,就是一个跳转指令JMP,跳到函数的首地址去,并从那里开始执行指令。
    比如下面的代码:
    C := Add(10, 20);
    按照上面的讨论,汇编代码应该如下:
    MOV EAX, 10
    MOV EDX, 20
    JMP @Add
    又遇到另一个问题:函数执行完后如何返回?为了解决这个问题,必须把 C := Add(10, 20)之后的指令地址保存起来。
    MOV EAX, 10
    MOV EDX, 20
    PUSH [EIP + Len]
    JMP @Add
    大概有人觉得函数调用实在是很常用的事情,于是干脆把最后两条指令合成一条,变成了Call,所以最后的汇编代码如下:
    MOV EAX, 10
    MOV EDX, 20
    CALL @Add
    函数执行完后怎么在栈中找到返回地址?解决这个问题的关键点就是栈平衡。
    假设它的代码是这样:
    Function Add(a, b: Integer): Integer;
    begin
    Result := a + b;
    end;
    那么汇编代码就是这样:
    ADD EAX, EDX
    POP EDX // 问题:为什么是EDX?估计随便放的,执行完上一句Add指令以后EDX是闲置的,可以随便使用。执行函数前,把前一个函数的栈顶地址压栈了,现在只需简单出栈即可,出栈到任意一个寄存器以供跳转即可。跳转之后,这个寄存器存储的值也不再需要了。
    JMP EDX
    同样后两个指令太常用了,因此合成一条,成了Ret,最后的汇编代码是这样的:
    ADD EAX, EDX
    RET
    从汇编角度函数调用大概就是如此。

    结论:

    ① 未优化的Pascal代码与优化的汇编代码效率相差为45倍。
    ② 优化的Pascal代码与优化的汇编代码效率相差为20倍。
    ③ 优化的Pascal代码与未优化的汇编代码效率相差为2.9位。
    ④ 未优化的汇编代码与优化的汇编效率相差为7倍。

    参考:
    http://blog.csdn.net/suiyunonghen/article/details/2501737
    http://blog.csdn.net/suiyunonghen/article/details/1909904
    http://blog.csdn.net/suiyunonghen/article/details/1897142
    http://blog.csdn.net/suiyunonghen/article/details/1897062

    BASM for Beginners
    http://dennishomepage.gugs-cats.dk/BASM-filer/BASMForBeginners1.htm

    --------------------------------------------------------------------------------------

    汇编中通用寄存器的目的

    1、EAX和AX:累加器,所有的I/O指令用它来与外部设备传送信息
    2、EBX和BX:在计算存储单元地址时常用作基地址寄存器
    3、ECX和CX:保存计数值
    4、EDX和DX:做四字或二字运算时,可以把EDX(DX)和EAX(AX)组合在一起存放一个四字或二字长的数据,在对某些I/O操作时,DX可以放I/O的端口地址
    5、ESP和SP:堆栈栈顶指针。
    6、EBP和BP:基址寄存器
    7、ESI和SI:源变址
    8、EDI和DI:目的变址

    返回值(对于intel C++, Visual C++, GCC而言):
    1. 如果是地址或者整数就放在eax中
    2. 如果字节类型就放在al中
    3. 如果是浮点数类型,就放在浮点数堆栈的栈顶

    浮点数常用指令(float占用4个字节,double占用8个字节):
    fld 压栈 fst 弹栈
    fcom 比较 fnstsw 将协处理器的标志寄存器的内容拷贝到通用寄存器
    fadd 加法 fdiv 除法 fmul 乘法 fsub 减法
    例如:
    float a=5.89+8.90
    fld 40BC7AE1h ; 压栈 5.89
    fadd 410E6666h; 加上 8.90
    fst [esp+var_4]; 将浮点堆栈顶部的值弹到变量中
    浮点堆栈一共占有8个单元,每个单元占8个字节,栈顶为st(0)或称st,栈底为st(7)
    fld float对应的机器码是 0xD9
    fld double对应的机器码是 0xDD
    fld long double对于的机器码是 0xDB

    除法运算比乘法慢10倍(不做优化的情况下),所以使用公式来优化:
    a/b = (2^n/b)*(a/2^n)

    VC++的Release版默认优化级别是O2

  • 相关阅读:
    Asp.net获取客户端的IP地址排除::1
    EF 筛选列包含NULL会报错
    layUI关于table编辑列支持方向键功能
    .NET CORE 发布IIS问题收集
    VS2019最新源代码管理工具+附下载地址
    关于Mysql可视化工具Navicat Premium12激活使用【亲测】
    经典SQL 语句
    事务的四种隔离级别 [转载]
    HTML 特殊符号编码对照表
    github本地文件Push到仓库
  • 原文地址:https://www.cnblogs.com/findumars/p/2743121.html
Copyright © 2011-2022 走看看