汇编语言程序设计


汇编语言程序设计

第二章

1         通用数据寄存器--以AX为例

  1.1         最大值:2^16-1

      例:在AX中存储18D

      18D

      -12H

      -10010B

  1.2         8086为16位寄存器,如何保证程序兼容性

      l  将通用寄存器分为两个独立的8位寄存器

      l  细分:AX可以分为AH和AL

  1.3         “字”在寄存器中的存储

      8086 是16位CPU

      l  8086的字长为16bit

      l  一个字可以存在一个16位寄存器中

2         mov和add指令(汇编语言不区分大小写)

  2.1         mov ax,18                 将18送入AX中                ax=18

      mov ah,78                将78送入AH中                ah=78

      add ax,8                   将寄存器AX的值加8        ax=ax+8

      mov ax,bx                 将bx值说送入ax中          ax=bx

      add ax,bx                  将ax,bx内容相加存入ax   ax=ax+bx

  2.2         在进行运算时无论是ah,al还是ax只要发生溢出,都会舍弃溢出值保留剩下的值

3         确定物理地址的方法

  3.1         cpu访问内存单元时要给出内存单元的地址

  3.2         所有的内存单元构成的存储空间是一个一维的线性空间

  3.3         每一个内存单元在这个空间中都有唯一的地址,这个唯一的地址称为物理地址

  3.4         事实8086有20位地址总线,可传送20位地址,寻址能力为1M(2^16)

  3.5         8086是16位结构的CPU

    3.5.1    运算器一次最多可以处理16位数据,寄存器的最大运算宽度为16位

    3.5.2    在8086内部处理、传输、暂存的地址也是16位,寻址能力只是64K

  3.6         解决方案:

    3.6.1    用两个16位地址(段地址、偏移地址)和成一个20位的物理地址

    3.6.2    地址加法器合成物理地址的方法:物理地址=段地址x16+偏移地址

    3.6.3    本质意义

       CPU在访问内存时,用一个基础地址(段地址x16)和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址

4         内存分段表示

  4.1         用分段的方式管理内存

    4.1.1    8086CPU用“(段地址x16)+偏移地址=物理地址”的方式给出内存单元的物理地址

    4.1.2    内存并没有分段,段的划分来自于CPU

    4.1.3    段地址x16必然是16的倍数,所以一个段的起始地址也一定是16的倍数

    4.1.4    偏移地址为16位,16位地址的寻址能力是64K,所以一个段地址的长度为64K。

    4.1.5    偏移地址16位,变化范围为0~FFFFH,用偏移地址最大寻址64K。

    4.1.6    例:数据在21F60H内存中,段地址是2000H,说法

      4.1.6.1    数据存在内存2000:1F60单元中(这里的2000是段地址,1F60是偏移地址)。

      4.1.6.2    数据存在内存中2000H段中的1F60H中。

      4.1.6.3    段地址很重要

        4.1.6.3.1   CS-代码段寄存器              DS-数据段寄存器

              SS-栈段寄存器                  ES-附加段寄存器

5         Debug调试工具

  5.1.1    Debug是DOS系统中的著名的调试程序,也可以运行在windows系统模式下

  5.1.2    使用Debug程序,可以观察CPU各种寄存器中内容,内存的情况,并且在机器指令级跟踪程序的运行。

  5.1.3    R-查看、改变CPU寄存器的内容

    5.1.3.1    R:查看寄存器的内容

    5.1.3.2    R 寄存器名:改变指定寄存器内容(空格可加可不加)

  5.1.4    T-单步调试,执行机器指令

    5.1.4.1    T:执行CS:IP中的指令

  5.1.5    D-查看内存中的内容

    5.1.5.1    D:列出预设地址内存处的128个字节的内容

    5.1.5.2    D 段地址:偏移地址:列出内存中指定地址处的内容

    5.1.5.3    D 段地址:偏移地址 结尾偏移地址:列出内存中指定地址范围内的内容

  5.1.6    E-改变内存中的内容

    5.1.6.1    E 段地址:偏移地址:数据1数据2

    5.1.6.2    E段地址:偏移地址

        逐个访问式修改

        空格:接受,继续

        回车:结束

        内存中的数据可以是数据,也可以是代码,完全取决于完美自己。

  5.1.7    U-将机器指令翻  译成汇编指令

    5.1.7.1    U 地址:查看代码

  5.1.8    A-以汇编指令的形式在机器中写入机器指令

    5.1.8.1    A 地址:写入汇编指令。(一般情况写在CS中,IP是偏移地址)出现错误继续输入就可以了。

  5.1.9    Q:退出Debug

  5.2         修改CS,IP指令

    5.2.1    事实:执行指令取决于CS:IP

    5.2.2    应用:可以通过改变CS:IP的内容,控制CPU主要执行的目标指令,但是现在是不通过debug修改的。

    5.2.3    指令修改的方法

      5.2.3.1    首先mov cs,2000h        mov ip,0000H 是不行的。

      5.2.3.2    唯一可以改变的是间接修改cs的值,且ip的值是无法间接修改的,也就是说,汇编中是不太支持,程序去修改内存地址的。

          Mov ax,2000H        赋值

          Mov cs,ax        可以运行

          Mov ip,ax        错误

        5.2.3.3    所以引用了跳转指令 jmp(转移指令)

          5.2.3.3.1   Jmp 段地址:偏移地址

                功能:用指令中给出的段地址修改CS,偏移地址修改IP

          5.2.3.3.2   仅修改IP的内容

                Jmp 某一合法寄存器

                Jmp ax(ax中保存的是一个偏移地址,类似于mov ip,ax(只是有相同的意思,但是现实中确是没有的))

6         内存中字的存储

  6.1         事实:对于8086CPU,16位为一个字

  6.2         问题:16位字的储存在一个16位的寄存器中,如何存储

      回答:高8位放在高字节,低8位放在低字节

  6.3         问题:16位的字在内存中需要2个连续字节,怎么存放

      回答:低字节存放在低8位,高字节存放在高8位

  6.4         字单元

      6.4.1    字单元:由两个地址连续的内存单元组成,存放一个字型数据(16位)

      6.4.2    原理:在一个字单元中,低地址单元存放的是低位字节,高地址单元存放高位字节。

7         DS和[address]实现字节的传送

  7.1         要求:CPU在读取一个内存单元的时候,必须先给出这个内存单元的地址

      原理:内存地址由段地址和偏移地址组成

      解决方案:DS和[address]

      用DS寄存器存放要访问的数据的段地址

      偏移地址用[…]形式直接访问

  7.2         将段地址存入DS两种方式

    7.2.1    Mov ds,1000h           (错的)

    7.2.2    Mov bx,1000h

        Mov ds,bx                 (对的)

        不支持直接将数据送入段地址中(硬件的设计问题)

       套路:数据->一般寄存器->段寄存器

8         DS与数据段-一般情况下降数据存入DS段地址中

9         栈及栈操作的实现

  9.1         栈是一种只能在一端进行插入或删除操作的数据结构

  9.2         栈有两个基本操作:出栈和入栈。

      入栈:将一个新的元素放到栈顶。

      出栈:从栈顶取出一个元素。

  9.3         栈顶的元素总是最后入栈,需要出栈时,又最是先被从栈中取出。

      栈底就是第一个进栈的数据,栈顶就是最后一个进栈的数据。

  9.4         栈的操作规则:LIFO(last in first out,后进先出)

  9.5         PUSH(入栈)和POP(出栈)指令

      push ax     :将ax的数据送入栈中

      pop ax        :从栈顶取出数据送人ax

      以字(16位)为单位对栈进行操作。

  9.6         CPU是如何知道一段内存空间被当做栈来使用

      栈段寄存器SS                 存放栈顶的段地址

      栈顶指针寄存器SP          存放栈顶的偏移地址

  9.7         执行push和pop的时候,如何知道那个单元时栈顶单元

      任意时刻,SS:SP指向栈顶元素

  9.8         过程

      push    ax

      (1)    SP=SP-2;

      (2)    将ax中的内容送入SS:SP指向的内存单元处,SS:SP此时指向新栈顶

      pop ax

      (1)    将SS:SP指向的内存单元的数据送入ax中

      (2)    SP=SP+2,SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶。

      (3)    栈越界的问题

         如何能够保证在入栈和出栈时,栈顶不会超过出栈空间。

相关