孤枝玉瘦 發表於 2022-10-3 21:03:00

王爽《汇编语言第二版》学习笔记

<p></p><div class="toc"><div class="toc-container-header">目录</div><ul><li>1 基础知识</li><li>2 寄存器<ul><li><ul><li>2.1 通用寄存器</li><li>2.3 几条汇编指令</li><li>2.4 8086CPU给出物理地址的方法</li><li>2.5 段的概念</li><li>2.6 段寄存器</li><li>2.7 修改CS、IP的指令</li></ul></li></ul></li><li>3 寄存器(内存访问)<ul><li><ul><li>3.1 DS和</li><li>3.2 CPU的栈机制</li><li>3.3 栈段</li></ul></li></ul></li><li>4 第一个程序<ul><li><ul><li>4.1 源程序</li><li>4.2 伪指令</li><li>4.3 标号</li><li>4.4 程序返回</li><li>4.5 语法错误和逻辑错误</li><li>4.6 EXE文件中程序的加载过程</li></ul></li></ul></li><li>5 和loop指令<ul><li><ul><li>5.1 loop指令</li><li>5.2 masm对指令的处理</li><li>5.3 算和问题</li><li>5.4 段前缀</li></ul></li></ul></li><li>6 包含多个段的程序<ul><li><ul><li>6.1 在代码段中使用数据</li><li>6.2 可执行文件的程序执行过程</li><li>6.3 可执行文件的组成</li><li>6.4 将数据、代码、栈放入不同的段</li></ul></li></ul></li><li>7 更灵活的定位内存地址的方法<ul><li><ul><li>7.1 and和or指令</li><li>7.2 </li><li>7.3 SI和DI</li><li>7.4 </li></ul></li></ul></li><li>8 数据处理的两个基本问题<ul><li><ul><li>8.1 bx、si、di和bp</li><li>8.2 机器指令处理的数据在哪里</li><li>8.3 汇编语言中数据位置的表达</li><li>8.4 寻址方式</li><li>8.5 要处理的数据有多长</li><li>8.6 dup</li></ul></li></ul></li><li>9 转移指令的原理<ul><li><ul><li>9.1 操作符offset</li><li>9.2 根据位移进行转移的jmp指令</li><li>9.3 转移的目的地址在指令中的jmp指令</li><li>9.4 转移地址在寄存器中的jmp指令</li><li>9.5 转移地址在内存中的jmp指令</li><li>9.6 jcxz指令</li><li>9.7 屏幕显示颜色字符</li></ul></li></ul></li><li>10 CALL和RET指令<ul><li><ul><li>10.1 ret和retf</li><li>10.2call指令</li><li>10.3 根据位移转移</li><li>10.4 根据目的地址进行转移</li><li>10.5 转移地址在寄存器中的call指令</li><li>10.6 转移地址在内存中的call指令</li><li>10.7 子程序</li></ul></li></ul></li><li>11 标志寄存器<ul><li><ul><li>11.1 ZF标志</li><li>11.2 PF标志</li><li>11.3 SF标志</li><li>11.4 CF标志</li><li>11.5 OF标志</li><li>11.6 adc指令</li><li>11.7 sbb指令</li><li>11.8 cmp指令</li><li>11.9 条件转移指令</li><li>11.10 DF标志和串传送指令</li><li>11.11 pushf和popf</li></ul></li></ul></li><li>12 内中断<ul><li><ul><li>12.1 内中断的产生</li><li>12.2 中断向量表</li><li>12.3 中断过程</li><li>12.4 中断处理程序和iret指令</li><li>12.5 编程处理0号中断</li><li>12.6 do0的安装</li><li>12.7 单步中断</li><li>12.8 响应中断的特殊情况</li></ul></li></ul></li><li>13 int指令<ul><li><ul><li>13.1 int指令</li><li>13.2 BIOS和DOS中断例程的安装过程</li><li>13.3 BIOS中断例程应用</li><li>13.4 DOS中断例程应用</li></ul></li></ul></li><li>14 端口<ul><li><ul><li>14.1 端口的读写</li><li>14.2 CMOS RAM芯片</li><li>14.3 shl和shr指令</li></ul></li></ul></li><li>15 外中断<ul><li><ul><li>15.1 外中断信息</li><li>15.2 PC机键盘的处理过程</li><li>15.3 编写int 9中断例程</li></ul></li></ul></li><li>16 直接定址表<ul><li><ul><li>16.1 描述单元长度的标号</li><li>16.2 在其他段中使用数据标号</li><li>16.3 直接定址表</li></ul></li></ul></li><li>17 使用BIOS进行键盘输入和磁盘读写<ul><li><ul><li>17.1 键盘处理</li><li>17.2 磁盘读写</li></ul></li></ul></li><li>18 CPU的三种工作模式<ul><li><ul><li>18.1 实模式</li><li>18.2 保护模式</li><li>18.3 虚拟8086模式</li></ul></li></ul></li><li>19 实验<ul><li><ul><li>19.1 屏幕显示颜色字符</li><li>19.2 利用栈倒序存储字符串</li><li>19.3编程处理0号中断</li></ul></li></ul></li><li>20 附录</li></ul></div><p></p>
<h2 id="1-基础知识">1 基础知识</h2>
<h2 id="2-寄存器">2 寄存器</h2>
<h4 id="21-通用寄存器">2.1 通用寄存器</h4>
<ul>
<li>8086CPU的寄存器都是16位的</li>
<li>AX、BX、CX、DX4个通用寄存器</li>
</ul>
<h4 id="23-几条汇编指令">2.3 几条汇编指令</h4>
<ul>
<li>汇编指令或寄存器的名称不区分大小写</li>
</ul>
<h4 id="24-8086cpu给出物理地址的方法">2.4 8086CPU给出物理地址的方法</h4>
<ul>
<li>通过两个16位地址合成一个20位物理地址</li>
<li>物理地址=短地址*16+偏移地址</li>
</ul>
<h4 id="25-段的概念">2.5 段的概念</h4>
<ul>
<li>内存并没有分段,段的划分来自于CPU</li>
<li>编程时按照需要,将若干地址连续的内存单元看做一个段</li>
</ul>
<h4 id="26-段寄存器">2.6 段寄存器</h4>
<ul>
<li>4个段寄存器:CS、DS、SS、ES</li>
<li>CS为代码段寄存器,IP为指令指针寄存器</li>
<li>任意时刻,CS:IP将指向的内容当做指令执行</li>
</ul>
<h4 id="27-修改csip的指令">2.7 修改CS、IP的指令</h4>
<ul>
<li>能够改变CS、IP的指令被称为转移指令</li>
<li>jmp 段地址:偏移地址</li>
<li>jmp 合法寄存器(仅修改IP)</li>
</ul>
<h2 id="3-寄存器内存访问">3 寄存器(内存访问)</h2>
<h4 id="31-ds和addr">3.1 DS和</h4>
<ul>
<li>DS寄存器通常用来存放要访问的数据的段地址</li>
<li>[...]表示一个内存单元,...表示内存单元的偏移地址</li>
<li>8086CPU不支持直接将数据送入段寄存器</li>
</ul>
<h4 id="32-cpu的栈机制">3.2 CPU的栈机制</h4>
<ul>
<li>CPU的入栈和出栈都是以字为单位进行的</li>
<li>任意时刻,SS:SP指向栈顶</li>
<li>push和pop也可以在内存单元之间传送数据</li>
</ul>
<h4 id="33-栈段">3.3 栈段</h4>
<ul>
<li>一段内存,既可以是存代码,也可以存数据,也可以是栈空间,关键在于CS\IP、DS、SS\SP的指向</li>
</ul>
<h2 id="4-第一个程序">4 第一个程序</h2>
<h4 id="41-源程序">4.1 源程序</h4>
<ul>
<li>源程序由指令、伪指令和标号组成</li>
</ul>
<h4 id="42-伪指令">4.2 伪指令</h4>
<ul>
<li>
<p>伪指令是由编译器来执行的指令,编译器根据伪指令来进行相关的编译工作</p>
</li>
<li>
<p>segment</p>
</li>
<li>
<p>end</p>
</li>
<li>
<p>assume</p>
</li>
</ul>
<h4 id="43-标号">4.3 标号</h4>
<ul>
<li>标号代表一个地址,segment前的标号被处理为一个段地址</li>
</ul>
<h4 id="44-程序返回">4.4 程序返回</h4>
<ul>
<li>mov ax, 4c00H</li>
<li>int 21H</li>
</ul>
<h4 id="45-语法错误和逻辑错误">4.5 语法错误和逻辑错误</h4>
<ul>
<li>编译时出现的错误是语法错误</li>
<li>运行时发生的错误是逻辑错误</li>
</ul>
<h4 id="46-exe文件中程序的加载过程">4.6 EXE文件中程序的加载过程</h4>
<ul>
<li>找到一段起始地址为SA:0的内存空间</li>
<li>在该区域内前256个字节,创建程序段前缀(PSP)的数据区,DOS利用PSP和程序进行通信</li>
<li>从第256字节处开始,装入程序</li>
<li>将该内存区的段地址存入DS,设置CS:IP指向程序入口(该内存区256字节处)</li>
</ul>
<h2 id="5-bx和loop指令">5 和loop指令</h2>
<ul>
<li>要完整描述内存单元:需要内存单元地址和长度(类型)</li>
<li>表示一个内存单元,bx存储偏移地址,ds存储段地址</li>
<li>定义的描述符号“()”:(ax)表示ax中的内容,(20000H)表示内存20000H单元中的内容(括号内为物理地址)</li>
<li>约定符号idata表示常量</li>
</ul>
<h4 id="51-loop指令">5.1 loop指令</h4>
<ul>
<li>
<p>CPU指令loops时,要进行两步:cx-1,若cs不为0跳转至s处指令,若为0向下执行</p>
</li>
<li>
<p>用mov设置cx的值,表示循环次数</p>
</li>
</ul>
<h4 id="52-masm对指令的处理">5.2 masm对指令的处理</h4>
<ul>
<li>mov al, ds:</li>
<li>mov al, (段地址默认在ds中)</li>
</ul>
<h4 id="53-算和问题">5.3 算和问题</h4>
<ul>
<li>将内存单元中的8位数据赋值到16位寄存器ax中,再将ax中的数据加到dx上,从而使两个运算对象的类型匹配且结果不超界</li>
</ul>
<h4 id="54-段前缀">5.4 段前缀</h4>
<ul>
<li>用于显式地指明内存单元段地址的"ds:"被称为段前缀</li>
</ul>
<h2 id="6-包含多个段的程序">6 包含多个段的程序</h2>
<h4 id="61-在代码段中使用数据">6.1 在代码段中使用数据</h4>
<ul>
<li>dw定义字型数据,db定义字节型数据,dd定义双字型数据</li>
<li>也可以说dw开辟了内存空间</li>
<li>在end start中,start标号指明了程序入口</li>
</ul>
<h4 id="62-可执行文件的程序执行过程">6.2 可执行文件的程序执行过程</h4>
<ul>
<li>由其他程序Debug、command等将程序加载到内存</li>
<li>设置CS:IP指向程序入口</li>
<li>程序运行结束,返回加载者</li>
</ul>
<h4 id="63-可执行文件的组成">6.3 可执行文件的组成</h4>
<ul>
<li>可执行文件由描述信息和程序组成</li>
<li>描述信息主要是编译、链接过程中对程序的伪指令进行处理获得的</li>
<li>加载者从描述信息中获取程序的入口地址</li>
</ul>
<h4 id="64-将数据代码栈放入不同的段">6.4 将数据、代码、栈放入不同的段</h4>
<ul>
<li>段名也是标号,代表了段地址,mov ax, data</li>
<li>start在code段中,这样CPU就将code段中的内容当做指令执行(CS不用设置,栈和数据段都需设置段地址)</li>
</ul>
<h2 id="7-更灵活的定位内存地址的方法">7 更灵活的定位内存地址的方法</h2>
<h4 id="71-and和or指令">7.1 and和or指令</h4>
<ul>
<li>and按位与,可用于置0</li>
<li>or按位或,可用于置1</li>
</ul>
<h4 id="72-bxidata">7.2 </h4>
<ul>
<li>表示一个内存单元</li>
<li>进行数组处理</li>
</ul>
<h4 id="73-si和di">7.3 SI和DI</h4>
<ul>
<li>SI和DI类似于BX,但不能分为两个8位寄存器</li>
</ul>
<h4 id="74-bxsidiidata">7.4 </h4>
<ul>
<li>
<p>mov ax, </p>
</li>
<li>
<p>mov ax, 200</p>
</li>
<li>
<p>mov ax, .200</p>
</li>
<li>
<p>需要暂存数据的时候,一般用栈,比如双重循环的cx计数问题</p>
</li>
</ul>
<h2 id="8-数据处理的两个基本问题">8 数据处理的两个基本问题</h2>
<ul>
<li>数据在哪里,有多长</li>
<li>reg表示寄存器,sreg表示段寄存器</li>
</ul>
<h4 id="81-bxsidi和bp">8.1 bx、si、di和bp</h4>
<ul>
<li>只有这四个寄存器能放在[...]中进行内存单元的寻址</li>
<li>要么单独出现,要么以下四个组合:bx\bp和si、bx\bp和di</li>
<li>只要在[...]中使用bp,默认的段地址在ss中</li>
</ul>
<h4 id="82-机器指令处理的数据在哪里">8.2 机器指令处理的数据在哪里</h4>
<ul>
<li>CPU内部、内存和端口</li>
</ul>
<h4 id="83-汇编语言中数据位置的表达">8.3 汇编语言中数据位置的表达</h4>
<ul>
<li>立即数、寄存器、段地址和偏移地址</li>
</ul>
<h4 id="84-寻址方式">8.4 寻址方式</h4>
<ul>
<li>用于定位内存单元的方法称为寻址方式</li>
<li>直接寻址</li>
<li>寄存器间接寻址</li>
<li>寄存器相对寻址</li>
<li>基址变址寻址</li>
<li>相对基址变址寻址</li>
</ul>
<h4 id="85-要处理的数据有多长">8.5 要处理的数据有多长</h4>
<ul>
<li>指令可以处理字节和字两种尺寸的数据</li>
<li>通过寄存器名指明要处理的数据尺寸</li>
<li>没有寄存器名的情况下,通过word/byte ptr指明内存单元长度</li>
</ul>
<h4 id="86-dup">8.6 dup</h4>
<ul>
<li>和db、dw、dd等数据定义伪指令配合使用,用来进行数据重复</li>
</ul>
<h2 id="9-转移指令的原理">9 转移指令的原理</h2>
<ul>
<li>只修改IP,称为段内转移</li>
<li>都修改,称为段间转移</li>
<li>段内转移分为短转移和近转移</li>
<li>CPU的转移指令类型:无条件、有条件、中断、过程、循环</li>
</ul>
<h4 id="91-操作符offset">9.1 操作符offset</h4>
<ul>
<li>功能是获取标号的偏移地址</li>
</ul>
<h4 id="92-根据位移进行转移的jmp指令">9.2 根据位移进行转移的jmp指令</h4>
<ul>
<li>jmp short 标号</li>
<li>机器码中包含的是转移的位移</li>
<li>jmp near ptr 标号</li>
</ul>
<h4 id="93-转移的目的地址在指令中的jmp指令">9.3 转移的目的地址在指令中的jmp指令</h4>
<ul>
<li>jmp far ptr标号是段间转移,又称为远转移</li>
</ul>
<h4 id="94-转移地址在寄存器中的jmp指令">9.4 转移地址在寄存器中的jmp指令</h4>
<h4 id="95-转移地址在内存中的jmp指令">9.5 转移地址在内存中的jmp指令</h4>
<ul>
<li>jmp word ptr 内存单元地址 (取偏移地址)</li>
<li>jmp dword ptr 内存单元地址 (高地址是段地址,低地址是偏移地址)</li>
</ul>
<h4 id="96-jcxz指令">9.6 jcxz指令</h4>
<ul>
<li>jcxz为有条件转移指令,所有条件转移指令都是短转移</li>
<li>cx=0则跳转到标号</li>
</ul>
<h4 id="97-屏幕显示颜色字符">9.7 屏幕显示颜色字符</h4>
<ul>
<li>显存中有一块80*25的彩色字符模式显示缓冲区,向该内存中写入数据,内容可以立即显示到显示器上</li>
<li>一个字符占两个字节,一个字节存放arscii码,一个字节存放属性</li>
</ul>
<h2 id="10-call和ret指令">10 CALL和RET指令</h2>
<h4 id="101-ret和retf">10.1 ret和retf</h4>
<ul>
<li>ret用栈中数据修改IP,实现近转移</li>
<li>retf用栈中数据修改CS:IP,实现远转移</li>
</ul>
<h4 id="102--call指令">10.2call指令</h4>
<ul>
<li>将IP和CS入栈</li>
<li>转移</li>
</ul>
<h4 id="103-根据位移转移">10.3 根据位移转移</h4>
<ul>
<li>call 标号 (近转移)</li>
</ul>
<h4 id="104-根据目的地址进行转移">10.4 根据目的地址进行转移</h4>
<ul>
<li>call far ptr (段间转移)</li>
</ul>
<h4 id="105-转移地址在寄存器中的call指令">10.5 转移地址在寄存器中的call指令</h4>
<ul>
<li>call 16位reg</li>
</ul>
<h4 id="106-转移地址在内存中的call指令">10.6 转移地址在内存中的call指令</h4>
<ul>
<li>call word ptr 内存单元地址</li>
<li>call dword ptr 内存单元地址</li>
</ul>
<h4 id="107-子程序">10.7 子程序</h4>
<ul>
<li>
<p>模块化程序设计</p>
</li>
<li>
<p>call和ret配合实现子程序</p>
</li>
<li>
<p>使用寄存器传参,或者使用栈传参</p>
</li>
<li>
<p>在子程序开始时,将要用到的寄存器中内容全部入栈,退出时恢复,用来解决寄存器冲突问题</p>
</li>
</ul>
<h2 id="11-标志寄存器">11 标志寄存器</h2>
<ul>
<li>8086的标志寄存器flag有16位,其中的信息被称为程序状态字(PSW)</li>
<li>flag寄存器是按位起作用的</li>
</ul>
<h4 id="111-zf标志">11.1 ZF标志</h4>
<ul>
<li>零标志位</li>
</ul>
<h4 id="112-pf标志">11.2 PF标志</h4>
<ul>
<li>奇偶标志位</li>
</ul>
<h4 id="113-sf标志">11.3 SF标志</h4>
<ul>
<li>符号标志位</li>
<li>做有符号数的运算时,可以通过它来得知结果正负</li>
<li>无符号数运算时,会影响值,但无意义</li>
</ul>
<h4 id="114-cf标志">11.4 CF标志</h4>
<ul>
<li>借位或进位标志位</li>
<li>用于无符号数运算</li>
</ul>
<h4 id="115-of标志">11.5 OF标志</h4>
<ul>
<li>溢出标志位</li>
<li>用于有符号数运算</li>
</ul>
<h4 id="116-adc指令">11.6 adc指令</h4>
<ul>
<li>带进位的加法</li>
<li>adc和add配合可以对更大的数据进行加法</li>
</ul>
<h4 id="117-sbb指令">11.7 sbb指令</h4>
<ul>
<li>带借位的减法</li>
</ul>
<h4 id="118-cmp指令">11.8 cmp指令</h4>
<ul>
<li>cmp a, b,计算差,但不保留结果,只影响flag寄存器</li>
<li>比较无符号数,看zf和cf</li>
<li>比较有符号数,看sf和of</li>
</ul>
<h4 id="119-条件转移指令">11.9 条件转移指令</h4>
<ul>
<li>和cmp配合使用</li>
<li>根据无符号数比较结果进行转移:je、jne、jb、jnb、ja、jna</li>
<li>二者配合使用时不用考虑标志寄存器,只用考虑逻辑含义</li>
</ul>
<h4 id="1110-df标志和串传送指令">11.10 DF标志和串传送指令</h4>
<ul>
<li>DF是方向标志位,在串处理指令中,控制每次操作后si和di的增减</li>
<li>DF=0是递增,DF=1是递减</li>
<li>movsb将ds:si指向的内存单元中的字节送入es:di中,然后根据df值,控制si\di增减</li>
<li>movsw是传送字单元</li>
<li>rep movsb根据cx的值,重复执行后面的串传送指令</li>
<li>cld和std</li>
</ul>
<h4 id="1111-pushf和popf">11.11 pushf和popf</h4>
<ul>
<li>用于将标志寄存器入栈和出栈</li>
</ul>
<h2 id="12-内中断">12 内中断</h2>
<h4 id="121-内中断的产生">12.1 内中断的产生</h4>
<ul>
<li>用中断类型码表示256种中断信息的来源</li>
<li>除法错误:0</li>
<li>单步执行:1</li>
<li>执行into指令:4</li>
<li>执行int n指令:n</li>
</ul>
<h4 id="122-中断向量表">12.2 中断向量表</h4>
<ul>
<li>
<p>用中断类型码通过中断向量表找到中断处理程序的入口地址</p>
</li>
<li>
<p>中断向量表在内存中保存,存放256个中断源对应的中断处理程序的入口地址</p>
</li>
<li>
<p>一个表项占两个字,高地址字存放段地址,低地址字存放偏移地址</p>
</li>
</ul>
<h4 id="123-中断过程">12.3 中断过程</h4>
<ul>
<li>CPU收到中断信息后,引发中断过程,之后将CS:IP指向程序入口,开始执行中断处理程序</li>
<li>中断过程:取得中断类型码,标志寄存器入栈,TF和IF置0,CS:IP入栈,读取程序入口地址</li>
<li>中断过程由硬件完成</li>
</ul>
<h4 id="124-中断处理程序和iret指令">12.4 中断处理程序和iret指令</h4>
<ul>
<li>中断处理程序步骤:保存用到的寄存器,处理中断,恢复用到的寄存器,用iret返回</li>
<li>iret:pop cs, pop ip, popf</li>
</ul>
<h4 id="125-编程处理0号中断">12.5 编程处理0号中断</h4>
<ul>
<li>0000:0000~0000:03ff空间中存放中断向量表,不会被其他程序使用</li>
<li>可以用0000:0200~0000:02ff的空间来存放中断处理程序</li>
<li>步骤:编写中断处理程序do0,将do0传送到目标内存,将do0入口地址写入0号表项</li>
</ul>
<h4 id="126-do0的安装">12.6 do0的安装</h4>
<ul>
<li>用rep movsb传送do0的字节</li>
<li>偏移地址是offset do0</li>
<li>通过编译器计算do0长度:offset do0end-offset do0</li>
<li>do0end: nop</li>
<li>汇编编译器可以处理表达式</li>
</ul>
<h4 id="127-单步中断">12.7 单步中断</h4>
<ul>
<li>CPU执行完一条指令后,如果检测到TF=1,则产生单步中断</li>
<li>解释了为什么在中断过程中要将TF置0:避免CPU永远执行单步中断程序的第一条指令</li>
<li>CPU提供单步中断功能为跟踪程序的执行过程,提供了实现机制</li>
</ul>
<h4 id="128-响应中断的特殊情况">12.8 响应中断的特殊情况</h4>
<ul>
<li>设置ss和sp的指令连续存放,为避免指向错误栈顶,CPU在两条指令之间不会引发中断过程</li>
</ul>
<h2 id="13-int指令">13 int指令</h2>
<h4 id="131-int指令">13.1 int指令</h4>
<ul>
<li>CPU执行int n指令,相当于引发一个n号中断的中断过程</li>
<li>系统将一些具有一定功能的子程序,以中断处理程序的方式提供给应用程序调用,又称为中断例程</li>
</ul>
<h4 id="132-bios和dos中断例程的安装过程">13.2 BIOS和DOS中断例程的安装过程</h4>
<ul>
<li>开机后,CPU加电,初始化CS:IP,自动从FFFF:0单元开始执行程序,该处有一条跳转指令,专区执行BIOS的硬件系统检测和初始化程序</li>
<li>初始化程序将建立BIOS所支持的中断向量,中断例程已固化到ROM中,一直在内存中</li>
<li>调用int 19H进行操作系统的引导,将操作系统从磁盘上加载到内存中,从此将计算机交给操作系统控制</li>
<li>DOS启动后,将它所提供的的中断例程装入内存,并建立中断向量</li>
</ul>
<h4 id="133-bios中断例程应用">13.3 BIOS中断例程应用</h4>
<ul>
<li>BIOS和DOS提供的中断例程,都用ah来传递内部子程序的编号</li>
</ul>
<h4 id="134-dos中断例程应用">13.4 DOS中断例程应用</h4>
<ul>
<li>mov ah, 4ch;   程序返回功能</li>
<li>mov al, 0;   返回值</li>
<li>int 21h;   中断</li>
</ul>
<h2 id="14-端口">14 端口</h2>
<ul>
<li>
<p>CPU在操控存储器时,把它们总的看做一个内存地址空间</p>
</li>
<li>
<p>和CPU通过总线相连的芯片除了存储器,还有各种接口卡上的接口芯片和主板上的接口芯片(连接外设)</p>
</li>
<li>
<p>这些芯片中,都有一组CPU可读写的寄存器,即端口</p>
</li>
<li>
<p>CPU的角度,对这些端口进行统一编址,建立了统一的端口地址空间</p>
</li>
<li>
<p>CPU可从以下三个地方读写数据:CPU内部寄存器、内存单元、端口</p>
</li>
</ul>
<h4 id="141-端口的读写">14.1 端口的读写</h4>
<ul>
<li>范围0~65535</li>
<li>读写指令in和out</li>
<li>只能使用ax或al从端口读入数据或发送数据,访问8位端口时用al,16位用ax</li>
<li>对256~65535的端口读写时,端口号要放到dx中</li>
</ul>
<h4 id="142-cmos-ram芯片">14.2 CMOS RAM芯片</h4>
<ul>
<li>PC机中,有一个CMOS RAM芯片,靠电池供电,关机后内部实时时钟仍然工作</li>
<li>0~0dh单元用于保存时间信息,其余大部分单元用来保存系统配置信息,供系统启动时BIOS程序读取</li>
<li>两个端口,70h用来存放访问RAM单元的地址,71用来存放访问的数据</li>
</ul>
<h4 id="143-shl和shr指令">14.3 shl和shr指令</h4>
<ul>
<li>shl是逻辑左移指令,左移一位,移出的送到CF中,最低位用0补充</li>
<li>如果移动位数大于1时,必须将移动数放到cl中</li>
</ul>
<h2 id="15-外中断">15 外中断</h2>
<ul>
<li>CPU通过端口和外部设备进行联系</li>
</ul>
<h4 id="151-外中断信息">15.1 外中断信息</h4>
<ul>
<li>外设的输入放到端口后,相关芯片向CPU发出中断信息,引发中断过程,处理外设的输入</li>
</ul>
<p>(1)可屏蔽中断</p>
<ul>
<li>CPU可以不响应的外中断,IF=0,不响应可屏蔽中断</li>
<li>可屏蔽中断的中断过程和内中断相同,只是中断类型码是通过数据总线送入CPU,而内中断类型码是在CPU内部产生的</li>
<li>sti和cli可以设置IF位</li>
</ul>
<p>(2)不可屏蔽中断</p>
<ul>
<li>CPU必须响应的外中断</li>
<li>中断类型码固定为2</li>
<li>几乎所有由外设引发的外中断,都是可屏蔽中断</li>
</ul>
<h4 id="152-pc机键盘的处理过程">15.2 PC机键盘的处理过程</h4>
<p>(1)键盘输入</p>
<ul>
<li>
<p>每个按键相当于一个开关,芯片对每个键的开关状态进行扫描</p>
</li>
<li>
<p>按下按键后,产生扫描码(通码),送入60h端口</p>
</li>
<li>
<p>松开按键后,产生扫描码(断码),送入60h端口</p>
</li>
</ul>
<p>(2)引发9号中断</p>
<ul>
<li>送入60h端口后,芯片向CPU发出9号中断,CPU响应中断,引发中断过程,执行int 9中断例程</li>
</ul>
<p>(3)执行int 9中断例程</p>
<ul>
<li>进行基本的键盘输入处理,如果是字符键,将扫描码和对应的arscii码送入内存中的BIOS键盘缓冲区;如果是控制键,写入存储状态字节的单元</li>
</ul>
<h4 id="153-编写int-9中断例程">15.3 编写int 9中断例程</h4>
<ul>
<li>
<p>int过程可以模拟为:</p>
</li>
<li>
<p>标志寄存器入栈,TF=1、IF=1,call dword ptr ds:</p>
</li>
<li>
<p>端口和中断机制,是CPU进行IO的基础</p>
</li>
</ul>
<h2 id="16-直接定址表">16 直接定址表</h2>
<h4 id="161-描述单元长度的标号">16.1 描述单元长度的标号</h4>
<ul>
<li>
<p>a db 1,2,3</p>
</li>
<li>
<p>标号a后没有“: ”,它是同时描述内存地址和单元长度的标号,可以代表内存单元</p>
</li>
<li>
<p>mov al, a</p>
</li>
<li>
<p>a被称为数据标号,而带": "的被称为地址标号(只能在代码段中使用)</p>
</li>
</ul>
<h4 id="162-在其他段中使用数据标号">16.2 在其他段中使用数据标号</h4>
<ul>
<li>如果想在代码段中直接使用其他段的数据标号访问数据,需要指定该段的段寄存器和段地址</li>
</ul>
<p>(1)存储标号偏移地址</p>
<ul>
<li>c dw a</li>
<li>此时数据标号c处存储的字型数据为a的偏移地址</li>
<li>相当于 c dw offset a</li>
</ul>
<p>(2)存储标号偏移地址和段地址</p>
<ul>
<li>c dd a</li>
<li>此时数据标号c处存储的双字型数据为a的偏移地址和段地址</li>
<li>相当于c dw offset a, seg a</li>
</ul>
<h4 id="163-直接定址表">16.3 直接定址表</h4>
<ul>
<li>table db '0123456789ABCDEF'</li>
<li>利用表,可以直接在两个集合(数字集合和字符集合)之间建立映射关系,通过查表,根据给出的数据(如0),可以得到其在另一集合中对应的数据(如'"0"')</li>
<li>通过数据,直接计算出所要找的元素的位置(表内偏移)的表,称为直接定址表</li>
</ul>
<h2 id="17-使用bios进行键盘输入和磁盘读写">17 使用BIOS进行键盘输入和磁盘读写</h2>
<ul>
<li>BIOS为这两种外设的IO提供了最基本的中断例程</li>
</ul>
<h4 id="171-键盘处理">17.1 键盘处理</h4>
<ul>
<li>int 9中断例程在有键按下时向键盘缓冲区写入数据</li>
<li>int 16h中断例程在应用程序对其调用时,将数据从键盘缓冲区读出</li>
</ul>
<h4 id="172-磁盘读写">17.2 磁盘读写</h4>
<ul>
<li>设置参数后,调用int 13h</li>
</ul>
<h2 id="18-cpu的三种工作模式">18 CPU的三种工作模式</h2>
<h4 id="181-实模式">18.1 实模式</h4>
<ul>
<li>实模式下,指令直接访问物理地址,通过段地址*16+偏移地址获得物理地址</li>
</ul>
<h4 id="182-保护模式">18.2 保护模式</h4>
<ul>
<li>
<p>为了实现进程隔离和多任务并发,引入了保护模式,同时为实现虚拟内存提供了硬件支持</p>
</li>
<li>
<p>通过分段和分页机制来进行保护和隔离</p>
</li>
</ul>
<p>(1)分段和分页</p>
<ul>
<li>
<p>分段:引入GDT(全局描述符,即段表),表中的表项称为段描述符,段寄存器中存放索引(段选择子),通过索引找到表项,获取段信息,加上偏移地址得到线性地址,目的是在寻址过程中保存保护信息(比如内存段属性)</p>
</li>
<li>
<p>分页:将虚拟内存划分为大小相同的页,同时物理空间也分为若干个物理块(页框),二者大小相等,离散分配,通过MMU查页表,实现页号到物理块号的映射,目的是将内存分块,将暂时不用的块放到磁盘上,扩展空间</p>
</li>
<li>
<p>分段是必须的,分页不是必须的</p>
</li>
<li>
<p>段是二维的,大小不固定,页是一维的,大小固定</p>
</li>
<li>
<p>保护模式下,每个段都设置了特权级,高特权级的代码可以对地特权级数据进行访问</p>
</li>
</ul>
<p>(2)四种地址</p>
<ul>
<li>
<p>虚拟地址是没有经过分段和分页转化的地址,是段寄存器和变址寄存器的组合</p>
</li>
<li>
<p>逻辑地址是用户可以操作的地址,即偏移地址</p>
</li>
<li>
<p>线性地址是虚拟地址经过分段转化后的地址,可以定位虚拟内存</p>
</li>
<li>
<p>物理地址是线性地址经过分页转化后的地址</p>
</li>
</ul>
<h4 id="183-虚拟8086模式">18.3 虚拟8086模式</h4>
<ul>
<li>
<p>使用户可以方便地在保护模式下运行一个或多个原8086程序</p>
</li>
<li>
<p>DOS系统中,CPU以实模式运行</p>
</li>
<li>
<p>Windows系统中,CPU以保护模式运行</p>
</li>
<li>
<p>想在Windows中运行DOS程序,CPU切换至虚拟8086模式</p>
</li>
</ul>
<h2 id="19-实验">19 实验</h2>
<h4 id="191-屏幕显示颜色字符">19.1 屏幕显示颜色字符</h4>
<h4 id="192-利用栈倒序存储字符串">19.2 利用栈倒序存储字符串</h4>
<h4 id="193--编程处理0号中断">19.3编程处理0号中断</h4>
<h2 id="20-附录">20 附录</h2>
<ul>
<li>数据可以分为字符和数字两种类型,在内存中都以二进制形式存储,其中字符存储arscii码(一个字节),数字存储补码(长度由具体数字类型决定)</li>
<li>关于内存单元的地址和内容:地址表示在几个字节处,内容表示存储了什么字节</li>
</ul><br><br>
来源:https://www.cnblogs.com/z5onk0/p/16751262.html
頁: [1]
查看完整版本: 王爽《汇编语言第二版》学习笔记