黄振贤 發表於 2020-3-16 00:01:00

汇编语言程序设计

<p align="center">汇编语言程序设计</p>
<p align="center">第二章</p>
<p>1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 通用数据寄存器--以AX为例</p>
<p>  1.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最大值:2^16-1</p>
<p>      例:在AX中存储18D</p>
<p>      18D</p>
<p>      -12H</p>
<p>      -10010B</p>
<p>  1.2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8086为16位寄存器,如何保证程序兼容性</p>
<p>      l&nbsp; 将通用寄存器分为两个独立的8位寄存器</p>
<p>      l&nbsp; 细分:AX可以分为AH和AL</p>
<p>  1.3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; “字”在寄存器中的存储</p>
<p>      8086 是16位CPU</p>
<p>      l&nbsp; 8086的字长为16bit</p>
<p>      l&nbsp; 一个字可以存在一个16位寄存器中</p>
<p>2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov和add指令(汇编语言不区分大小写)</p>
<p>  2.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov ax,18&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将18送入AX中&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ax=18</p>
<p>      mov ah,78&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将78送入AH中&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ah=78</p>
<p>      add ax,8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将寄存器AX的值加8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ax=ax+8</p>
<p>      mov ax,bx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将bx值说送入ax中&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ax=bx</p>
<p>      add ax,bx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将ax,bx内容相加存入ax&nbsp;&nbsp; ax=ax+bx</p>
<p>  2.2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在进行运算时无论是ah,al还是ax只要发生溢出,都会舍弃溢出值保留剩下的值</p>
<p>&nbsp;</p>
<p>3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 确定物理地址的方法</p>
<p>  3.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cpu访问内存单元时要给出内存单元的地址</p>
<p>  3.2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 所有的内存单元构成的存储空间是一个一维的线性空间</p>
<p>  3.3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 每一个内存单元在这个空间中都有唯一的地址,这个唯一的地址称为物理地址</p>
<p>  3.4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 事实8086有20位地址总线,可传送20位地址,寻址能力为1M(2^16)</p>
<p>  3.5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8086是16位结构的CPU</p>
<p>    3.5.1&nbsp;&nbsp;&nbsp; 运算器一次最多可以处理16位数据,寄存器的最大运算宽度为16位</p>
<p>    3.5.2&nbsp;&nbsp;&nbsp; 在8086内部处理、传输、暂存的地址也是16位,寻址能力只是64K</p>
<p>  3.6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 解决方案:</p>
<p>    3.6.1&nbsp;&nbsp;&nbsp; 用两个16位地址(段地址、偏移地址)和成一个20位的物理地址</p>
<p>    3.6.2&nbsp;&nbsp;&nbsp; 地址加法器合成物理地址的方法:物理地址=段地址x16+偏移地址</p>
<p>    3.6.3&nbsp;&nbsp;&nbsp; 本质意义</p>
<p>       CPU在访问内存时,用一个基础地址(段地址x16)和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址</p>
<p>4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 内存分段表示</p>
<p>  4.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用分段的方式管理内存</p>
<p>    4.1.1&nbsp;&nbsp;&nbsp; 8086CPU用“(段地址x16)+偏移地址=物理地址”的方式给出内存单元的物理地址</p>
<p>    4.1.2&nbsp;&nbsp;&nbsp; 内存并没有分段,段的划分来自于CPU</p>
<p>    4.1.3&nbsp;&nbsp;&nbsp; 段地址x16必然是16的倍数,所以一个段的起始地址也一定是16的倍数</p>
<p>    4.1.4&nbsp;&nbsp;&nbsp; 偏移地址为16位,16位地址的寻址能力是64K,所以一个段地址的长度为64K。</p>
<p>    4.1.5&nbsp;&nbsp;&nbsp; 偏移地址16位,变化范围为0~FFFFH,用偏移地址最大寻址64K。</p>
<p>    4.1.6&nbsp;&nbsp;&nbsp; 例:数据在21F60H内存中,段地址是2000H,说法</p>
<p>      4.1.6.1&nbsp;&nbsp;&nbsp; 数据存在内存2000:1F60单元中(这里的2000是段地址,1F60是偏移地址)。</p>
<p>      4.1.6.2&nbsp;&nbsp;&nbsp; 数据存在内存中2000H段中的1F60H中。</p>
<p>      4.1.6.3&nbsp;&nbsp;&nbsp; 段地址很重要</p>
<p>        4.1.6.3.1&nbsp;&nbsp; CS-代码段寄存器&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DS-数据段寄存器</p>
<p>            &nbsp; SS-栈段寄存器&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ES-附加段寄存器</p>
<p>5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Debug调试工具</p>
<p>  5.1.1&nbsp;&nbsp;&nbsp; Debug是DOS系统中的著名的调试程序,也可以运行在windows系统模式下</p>
<p>  5.1.2&nbsp;&nbsp;&nbsp; 使用Debug程序,可以观察CPU各种寄存器中内容,内存的情况,并且在机器指令级跟踪程序的运行。</p>
<p>  5.1.3&nbsp;&nbsp;&nbsp; R-查看、改变CPU寄存器的内容</p>
<p>    5.1.3.1&nbsp;&nbsp;&nbsp; R:查看寄存器的内容</p>
<p>    5.1.3.2&nbsp;&nbsp;&nbsp; R 寄存器名:改变指定寄存器内容(空格可加可不加)</p>
<p>  5.1.4&nbsp;&nbsp;&nbsp; T-单步调试,执行机器指令</p>
<p>    5.1.4.1&nbsp;&nbsp;&nbsp; T:执行CS:IP中的指令</p>
<p>  5.1.5&nbsp;&nbsp;&nbsp; D-查看内存中的内容</p>
<p>    5.1.5.1&nbsp;&nbsp;&nbsp; D:列出预设地址内存处的128个字节的内容</p>
<p>    5.1.5.2&nbsp;&nbsp;&nbsp; D 段地址:偏移地址:列出内存中指定地址处的内容</p>
<p>    5.1.5.3&nbsp;&nbsp;&nbsp; D 段地址:偏移地址 结尾偏移地址:列出内存中指定地址范围内的内容</p>
<p>  5.1.6&nbsp;&nbsp;&nbsp; E-改变内存中的内容</p>
<p>    5.1.6.1&nbsp;&nbsp;&nbsp; E 段地址:偏移地址:数据1数据2</p>
<p>    5.1.6.2&nbsp;&nbsp;&nbsp; E段地址:偏移地址</p>
<p>        逐个访问式修改</p>
<p>        空格:接受,继续</p>
<p>        回车:结束</p>
<p>        内存中的数据可以是数据,也可以是代码,完全取决于完美自己。</p>
<p>  5.1.7&nbsp;&nbsp;&nbsp; U-将机器指令翻 &nbsp;译成汇编指令</p>
<p>    5.1.7.1&nbsp;&nbsp;&nbsp; U 地址:查看代码</p>
<p>  5.1.8&nbsp;&nbsp;&nbsp; A-以汇编指令的形式在机器中写入机器指令</p>
<p>    5.1.8.1&nbsp;&nbsp;&nbsp; A 地址:写入汇编指令。(一般情况写在CS中,IP是偏移地址)出现错误继续输入就可以了。</p>
<p>  5.1.9&nbsp;&nbsp;&nbsp; Q:退出Debug</p>
<p>  5.2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 修改CS,IP指令</p>
<p>    5.2.1&nbsp;&nbsp;&nbsp; 事实:执行指令取决于CS:IP</p>
<p>    5.2.2&nbsp;&nbsp;&nbsp; 应用:可以通过改变CS:IP的内容,控制CPU主要执行的目标指令,但是现在是不通过debug修改的。</p>
<p>    5.2.3&nbsp;&nbsp;&nbsp; 指令修改的方法</p>
<p>      5.2.3.1&nbsp;&nbsp;&nbsp; 首先mov cs,2000h&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov ip,0000H 是不行的。</p>
<p>      5.2.3.2&nbsp;&nbsp;&nbsp; 唯一可以改变的是间接修改cs的值,且ip的值是无法间接修改的,也就是说,汇编中是不太支持,程序去修改内存地址的。</p>
<p>          Mov ax,2000H &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 赋值</p>
<p>          Mov cs,ax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以运行</p>
<p>          Mov ip,ax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 错误</p>
<p>        5.2.3.3&nbsp;&nbsp;&nbsp; 所以引用了跳转指令 jmp(转移指令)</p>
<p>          5.2.3.3.1&nbsp;&nbsp; Jmp 段地址:偏移地址</p>
<p>            &nbsp;   功能:用指令中给出的段地址修改CS,偏移地址修改IP</p>
<p>          5.2.3.3.2&nbsp;&nbsp; 仅修改IP的内容</p>
<p>              &nbsp; Jmp 某一合法寄存器</p>
<p>              &nbsp; Jmp ax(ax中保存的是一个偏移地址,类似于mov ip,ax(只是有相同的意思,但是现实中确是没有的))</p>
<p>6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 内存中字的存储</p>
<p>  6.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 事实:对于8086CPU,16位为一个字</p>
<p>  6.2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 问题:16位字的储存在一个16位的寄存器中,如何存储</p>
<p>      回答:高8位放在高字节,低8位放在低字节</p>
<p>  6.3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 问题:16位的字在内存中需要2个连续字节,怎么存放</p>
<p>      回答:低字节存放在低8位,高字节存放在高8位</p>
<p>  6.4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 字单元</p>
<p>      6.4.1&nbsp;&nbsp;&nbsp; 字单元:由两个地址连续的内存单元组成,存放一个字型数据(16位)</p>
<p>      6.4.2&nbsp;&nbsp;&nbsp; 原理:在一个字单元中,低地址单元存放的是低位字节,高地址单元存放高位字节。</p>
<p>7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DS和实现字节的传送</p>
<p>  7.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 要求:CPU在读取一个内存单元的时候,必须先给出这个内存单元的地址</p>
<p>      原理:内存地址由段地址和偏移地址组成</p>
<p>      解决方案:DS和</p>
<p>      用DS寄存器存放要访问的数据的段地址</p>
<p>      偏移地址用[…]形式直接访问</p>
<p>  7.2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将段地址存入DS两种方式</p>
<p>    7.2.1&nbsp;&nbsp;&nbsp; Mov ds,1000h&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (错的)</p>
<p>    7.2.2&nbsp;&nbsp;&nbsp; Mov bx,1000h</p>
<p>        Mov ds,bx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (对的)</p>
<p>        不支持直接将数据送入段地址中(硬件的设计问题)</p>
<p>       套路:数据-&gt;一般寄存器-&gt;段寄存器</p>
<p>8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DS与数据段-一般情况下降数据存入DS段地址中</p>
<p>9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 栈及栈操作的实现</p>
<p>  9.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 栈是一种只能在一端进行插入或删除操作的数据结构</p>
<p>  9.2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 栈有两个基本操作:出栈和入栈。</p>
<p>      入栈:将一个新的元素放到栈顶。</p>
<p>      出栈:从栈顶取出一个元素。</p>
<p>  9.3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 栈顶的元素总是最后入栈,需要出栈时,又最是先被从栈中取出。</p>
<p>      栈底就是第一个进栈的数据,栈顶就是最后一个进栈的数据。</p>
<p>  9.4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 栈的操作规则:LIFO(last in first out,后进先出)</p>
<p>  9.5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PUSH(入栈)和POP(出栈)指令</p>
<p>      push ax&nbsp;&nbsp; &nbsp; :将ax的数据送入栈中</p>
<p>      pop ax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :从栈顶取出数据送人ax</p>
<p>      以字(16位)为单位对栈进行操作。</p>
<p>  9.6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CPU是如何知道一段内存空间被当做栈来使用</p>
<p>      栈段寄存器SS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 存放栈顶的段地址</p>
<p>      栈顶指针寄存器SP&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 存放栈顶的偏移地址</p>
<p>  9.7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 执行push和pop的时候,如何知道那个单元时栈顶单元</p>
<p>      任意时刻,SS:SP指向栈顶元素</p>
<p>  9.8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 过程</p>
<p>      push&nbsp;&nbsp;&nbsp; ax</p>
<p>      (1)&nbsp;&nbsp;&nbsp; SP=SP-2;</p>
<p>      (2)&nbsp;&nbsp;&nbsp; 将ax中的内容送入SS:SP指向的内存单元处,SS:SP此时指向新栈顶</p>
<p>      pop ax</p>
<p>      (1)&nbsp;&nbsp;&nbsp; 将SS:SP指向的内存单元的数据送入ax中</p>
<p>      (2)&nbsp;&nbsp;&nbsp; SP=SP+2,SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶。</p>
<p>      (3)&nbsp;&nbsp;&nbsp; 栈越界的问题</p>
<p>         如何能够保证在入栈和出栈时,栈顶不会超过出栈空间。</p><br><br>
来源:https://www.cnblogs.com/-xxhh-/p/12501213.html
頁: [1]
查看完整版本: 汇编语言程序设计