SLP(Chapter 3):代码表示

0. 引子

Why 汇编

CPU不能理解,如 c = (a + b) * d
但是CPU可以理解,如将这俩个寄存器的值相加,并将结果存在第一个寄存器中

基础知识

编译

  1. 数据和代码在内存中分开存储
  • 代码(存储在cs+ip)
    mov eax,dword ptr[ebp-4]
    (1)C语言代码与汇编代码并不是一一对应,可以一对
    (2)汇编窗口显示的地址是机器码的地址,而不是汇编的地址,因为虚拟内存执行的字节流,要不是机器码,要不是数据
    (3)机器码长度不同,用后一个指令地址减去前一个指令地址得到

  • 数据(存储在stack+ebp)
    in stack, accessed via [ebp-4]

    最多一个16位的寄存器只能编216个地址,这样决定了寻址的能力只有64K,所以每一个段大小为64K。但是有20根数据线,所以段地址(可以理解成对字的寻址左移四位(十六进制x10H)得到物理地址

    段寄存器:在8086系统中,访问存储器的地址码由段地址和段内偏移地址两部分组成。段寄存器用来存放各分段的逻辑基值,并指示当前正在使用的4个逻辑段,包括以下:
      1, 代码段寄存器CS:存放当前正在运行的程序代码所在段的段基值,表示当前使用的指令代码可以从该段寄存器指定的存储器段中取得,相应的偏移值则由IP提供。
      2, 数据段寄存器DS:指出当前程序使用的数据所存放段的最低地址,即存放数据段的段基值。
      3, 堆栈段寄存器SS:指出当前堆栈的底部地址,即存放堆栈段的段基值。
      4, 附加段寄存器ES:指出当前程序使用附加数据段的段基址,该段是串操作指令中目的串所在的段。

    1.2 (操作数)寻址模式 (operand-)addressing mode

    什么是寻址模式 addressing moder> 机器指令是计算机CPU可执行的指令,一条指令要包含操作符和操作的对象(操作数)。对于Intel Processors指令集而言,有的指令没有操作数,有的有多个操作数(大于1个)。
    所谓寻址模式,就是我们写的代码要指明操作数在那里,这样CPU才能正确的找到操作数,执行这条指令。

    提取哪个数据项r> 在 c 中 :使用变量
    在机器代码中:操作数寻址模式

    (操作数)寻址模式分为三类:(mov 目的操作数,源操作数)

    类型 解释 源操作数 目的操作数 例子 备注
    Immediate立即寻址 一条指令的操作数,可以直接包含在指令中,不需要去别的地方寻找 寄存器 寄存器 mov ax,10H 数据存储在代码段
    Register 放在寄存器 常量 寄存器 mov ax,bx 寄存器大小相等
    Memory 操作数放在内存中
    有的是取这个内存地址的数据就可以,所谓直接方式
    有的需要计算得出其存放地址,再通过地址取得内存中的数据,所谓间接方式。
    一个操作数必须是内存地址,另一个操作数可以是直接编 或寄存器 mov ax, [10H]
    mov ax, [bx]
    需要将DS的值左移4位(即十六进制的x10H)

    规律
    1. 立即数immediate只能显示为源操作数。
    2. 不允许进行内存到内存操作,但字符串操作(movs)除外
    3. 避免使用段寄存器。
    4. 有些操作数是显式指定的,有些则是隐含的。

    每条指令都包含:

    1. Function:指令的基本功能
    2. Affection:指令的执行对Flag R/ PSW 标志位的影响
    3. Data-addressing mode: 寻址方式
    4. Limitation: 寄存器使用上的要求和限制

    指令分类:
    栈是字Word之间的顺序
    大小端是字内字节顺序:x86是小端,字内的低字节在前

    类型 例子
    Data transforming/数据传送类 MOV dest,source
    lea,加载内存位置的有效地址
    PUSH AX 表示 AH 将移动到 SP-1 寻址的堆栈段内存位置,而 AL 将移动到 SP-2
    POP BX 将导致从堆栈中删除前两个字节的数据,并将第一个字节移动到 BL,将第二个字节移动到 BH 中
    Arithmetic operation/算术运算类 ADD (Add), ADC (Add with carry), INC (Increment by 1)
    SUB (Subtraction ), SBB (Subtraction with borrow ), DEC (Decrement by 1 ), NEG (Two’s complement negation)
    CMP (Compare operands )不改变目的操作数,只改变标志位的减法
    MUL (Unsigned multiply ), IMUL (Signed multiply )
    DIV (Unsigned divide), IDIV (Signed divide )
    CBW (Convert byte to word), CWD (Convert word to doubleword )
    Bits and logic operation/位与逻辑运算类 NOT, AND, OR, XOR
    TEST (Logical compare (AND) )//不改变目的操作数,只改变标志位的ADD
    SHL, SHR
    SAL, SAR
    ROL (Rotate left ), ROR (Rotate right )
    RCL (Rotate left (with carry) ), RCR (Rotate right (with carry) )
    String operation/字符串处理类 STOS 指令将数据存储在 AL、AX 或 EAX 中,位置由 DI 严格器寻址的额外段内存位置
    MOVSB (Move byte from string to string)
    STOSB (Store byte in string ), LODSB (Load byte)
    CMPSB (Compare bytes in memory)
    SCASB (Compare byte string)
    Branch and loop/控制转移类 JMP 是一个无条件的跳转指令
    call通过更改 ip 甚至 cs 寄存器将流重定向到刚刚调用的过程。CALL 指令与跳转指令不同,在堆栈上保存返回地址,RET后继续call的下一条指令
    CPU control/处理器控制类 CLC (Clear carry flag), STC (Set carry flag), CMC (Complement carry flag)
    CLD( Clear direction flag ),STD (Set direction flag )
    CLI (Clear interrupt flag ),STI (Set interrupt flag )
    NOP (No operation )
    HLT (Enter halt state)halts the CPU until the next external interrupt is fired.
    WAIT (Wait until not busy )
    LOCK (Assert BUS LOCK# signal ) (for multiprocessing)
    ESC (Escape)

    前缀: REPxx (重复 xx, xx可以是CMPS/MOVS/SCAS/STOS ) /REPZ

    例子:

    1. ECX + REP 重复

    将 eax (0CCCCCCCCh)的值ecx(14h)次写入 由 edi 寻址存位置,edi 在每次迭代中自动增加 4(因为每次是写入的双字)。
    2. 分支
    JE/JNE:jump equal / not equal

    3. 编写x86汇编程序(与CPU相关)

    就像其它任何一种语言一样,光有指令是无法完成一个完整的程序,还需要宏定义,程序结构,库调用等等

    汇编器和编译器

    相同点:都将一种语言转换为另一种语言
    不同点:编译器更智能、更复杂,因为它分析代码的含义、通过生成较小的可执行文件来优化程序或提高执行效率。汇编器只根据制造商的准则将指令转换为机器代码。一些汇编器也可以执行一些简单的指令集进行特定优化。

    两种类型的汇编语言(都可以生成x86的汇编指令集)

    1. GAS(GNU Assember)/AT&T
      GNU计划,又称革奴计划,是由Richard Stallman在1983年9月27日公开发起的。它的目标是创建一套完全自由的操作系统.。GNU汇编器(GNU Assembler),简称为GAS
    2. Intel/MASM Microsoft Macro Assembler
      VC ++ IDE使用的,是使用intel语法的x86汇编器

    The difference:
    两者的源操作数和目的操作数的位置相反
    前者的汇编指令中带有后缀(如b/w/l),指示操作数的长度(8/16/32 bits)
    前者在寄存器前加“%”,在常数和符 地址前加“$”
    前者间接寻址用( )表示,而后者用[ ]表示

    E.g:
    movl %edx,%eax mov eax,edx
    movl (%edx),%eax mov eax,[edx]

    汇编代码

    汇编程序

    常量

    1. 整数常量
      例如:-10、42d、10001101b、0FF3Ah、777o
      下标: b = 二进制,d = 十进制,h = 十六进制,o = 八进制
    2. 字符和字符串常量
      单引 或双引 中的字符串或字符串
      示例:A,“d”,ABC,“ABC”,“single quote ’ inside”, ‘double quote ” inside’
      每个 ASCII 字符占用一个字节

    程序包括

    • 可执行指令 executable
    • 伪指令directives:伪指令不属于指令集,所以不可执行。用于定义段、内存变量
    • 宏指令 marcos:是源程序中的一段有独立功能的程序代码。由汇编器转换为真实指令,目的是简化程序员任务

    前两个都是规定的,最后一个是你自己设计的。

    x86指令格式:

    • .TITLE 标题行(可选)
      包含程序和磁盘文件名的简短标题
    • .MODEL
      指定内存配置
      出于我们的目的,FLAT 内存模型将在同一 seg 中使用//数据代码
      线性 32 位地址空间(无分段)
      STDCALL 指令告诉汇编器使用 …
      名称和过程调用的标准约定
    • .686 处理器指令
      在MODEL指令之前使用。
      程序可以使用奔腾 P6 架构的说明
      至少.686 指令使用 FLAT 内存
    • .STACK 堆栈指令
      告诉汇编程序为程序定义运行时堆栈
      堆栈的大小可以由此指令有选择地指定
      过程调用需要运行时堆栈
    • .DATA 数据指令
      为程序数据定义内存中的区域
      程序变量应在此指令下定义
      汇编程序将分配和初始化变量的存储
    • .CODE 指令
      定义包含指令的程序的代码部分
      汇编器将指令放在内存中的代码区域
    • PROC 和 ENDP 指令
      用于定义过程
      作为一个约定,我们将主定义为第一个过程
      其他过程可以在主
    • 结束指令
      标记程序的结束
      标识程序启动过程的名称(主)

    inc一般是include文件用于编写同用代码的
    bin二进制文件,其用途依系统或应用而定 ,也可是 镜像文件
    com/DOS可执行命令文件,一般小于64KB

    4. 反汇编

    • 可以在可执行文件或 .o 文件上运行
    • 分析位模式的指令集
    • 生成装配代码的近似再现

    Register Allocation

    编译器希望能够为源程序中的每个变量分配一个寄存器,因为寄存器中变量会加快程序执行速度

    汇编语言:程序员

    C 语言:编译器

    分配寄存器很难,编译器不会尝试以尽可能最好的方式分配寄存器

    为什么r> 最好的方式意义冲突(长时间的分析和思考,结果不容易被理解)

    优化级别
    编译器优化寄存器分配的程度取决于优化级别

    • 高:开发后
      导致更激进的优化,需要更长的时间来编译
      对于人和调试器来说,很难将生成的机器代码与原始源代码相关联
    • 低:开发期间
      导致执行缓慢

    5. 机器码

    我们如何获得代码地址、找出代码的大小h2>

    使用 IDE 中的反汇编窗口,内存窗口

    全局变量是用的绝对地址,而局部变量是相对地址

    列表文件 listing file:使用它查看程序是如何汇编的
    map file: LST为扩展名,列表文件同时给出源程序和机器语言程序(每个段都有),使调试程序变得方便。LST文件可有可无

    SLP(Chapter 3):代码表示

    如何获得汇编代码对于的机器码

    1. 我们查找指令表,找到指令”mov”,并在操作码字段上写下相应的 6 位。
    2. 控制位
      D 指示数据流的方向,从内存到寄存器或寄存器到内存。在这种情况下,源代码存储在内存中,目标数据存储在寄存器 EAX 中,因此 D 设置为 1。
      W 指示操作数是否为单词。1 表示单词 。
      Mod 表示寻址模式,01 表示我们在这里使用的寄存器相对模式。
      REG 指示用于保存操作数的寄存器,eax 的代码为 000,因此我们在此处填 充 000。
      R/M 指示在寻址模式下使用哪个寄存器,ebp 的代码为 110。
    3. 最后一步是将相对地址 -4 附加到最右侧的 8 位。-4 表示在 2 的补数中。

    声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2020年1月3日
下一篇 2020年1月3日

相关推荐