《汇编语言》第四版笔记

第一章 基础知识

知识点

  • 总线宽度:该总线有N个根线,则可以说这个总线的宽度为N

  • 主板:主板上有一些重要器件,器件通过总线连接。这些器件有CPU,存储器,外围芯片组,拓展插槽等。拓展插槽一般插有RAM内存条和各类接口卡

  • 接口卡:CPU通过总线向接口卡发送命令,接口卡根据CPU命令对外设进行控制

  • 从存储器的功能和连接上,可以分为以下几类

    • 随机存储器RAM:
      主随机存储器一般由两个位置上的RAM组成:装在主板上的RAM和插在拓展槽的RAM
    • 装有BIOS(基本输入输出系统)的ROM:
      BIOS是由主板和各类接口卡的厂商提供的软件系统,可以通过它对硬件系统进行基本输入输出
    • 接口卡上的RAM:
      某些接口卡需要存储大批量数据,上面就装有RAM,比如显卡里的显存

  • CPU把所有的存储器看作一个假想的逻辑存储器(又称内存地址空间)去使用

  • 内存地址空间的大小受CPU地址总线宽度的限制

第二章 寄存器

知识点

  • 通用寄存器:用来存放一般数据的寄存器,如AX,BX,CX,DX
  • 因为以前的寄存器都是八位的,为了保证兼容,8086的16位寄存器可以拆分成两个独立的寄存器单独使用。如:AX可以拆分为AH和AL
  • 因此8086CPU的寄存器可以一次处理两种尺寸的数据:字节(8位)和字(16位)
  • 对于汇编指令 add al,93H
    al是当作一个单独的寄存器来使用的,如果结果溢出,高位并不会放入ah寄存器
  • 一个合法的汇编指令,指令的两个操作对象位数应该是一致的,以下指令不合法:
    mov ax,bl (8位寄存器和16位寄存器之间传数据
    mov al,20000 (8位数据存不了20000
  • 8086CPU是16位的,但是地址总线是20位的,不能让这16位字长限制了寻址范围,因此8086CPU采用两个16位地址合成一个20位物理地址的方法
  • 两个16位地址一个是段地址,另一个是偏移地址,通过一个加法器算出物理地址
  • 地址计算公式:段地址*16+偏移地址=物理地址
    含义:用一个基础地址(段地址*16(乘16在十六进制里就是左移一位))和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址
    既然是通过相对的关系得出物理地址,所以一个物理地址可以有多种表示形式
  • CPU可以将若干连续的内存单元看作一个段。段的大小受机器字长影响,8086CPU为16位,因此一个段的大小不能超过64KB
  • 段地址由CPU中的段寄存器提供,CS就是其中一个段寄存器
  • CS(存指令段地址)和IP(存指令偏移地址)是8086CPU两个关键的寄存器
    任意时刻,设CS的内容为M,IP内容为N,CPU将从内存:M*16+N单元开始读取指令并执行
  • 正常来说,CPU更新IP的时机:取出指令后,在指令执行之前
  • 同时修改CS,IP:jump 段地址:偏移地址(用指令中的段地址修改CS,偏移地址修改IP)
  • 仅修改IP,JUMP 寄存器 (用寄存器中的值修改IP)

预备知识:debug的使用

  • R命令查看,改变CPU寄存器的内容
    • 改变寄存器内容:r命令+寄存器
  • D命令查看内存中的内容
    • 列出从指定内存单元开始的128个内存单元的内容:d 段地址:偏移地址
    • 在使用“d 段地址:偏移地址”之后,用d命令查看后续内存内容
    • 指定内存查看范围:d 段地址:起始偏移地址 结尾偏移地址
    • 列出的内容分为3部分:左边是地址,中间是内容,右边是各内存单元中的数据对应的ASCII码,如果没有对应的,用'.'代替
  • E命令改写内存中的内容
    • 连续修改内存内容:e 起始地址 数据 数据...
    • 采用提问方式逐个改写内容:
      1.e 段地址:偏移地址,按enter键
      2.输入新数据+空格/空格
      3.希望改写的单元改写完毕后,按enter键
    • e命令可以写入数据,字符,字符串
  • U命令将内存中的机器码翻译成汇编指令
  • T命令执行一条机器指令
  • A命令以汇编的形式在内存中写入指令

第三章寄存器

知识点

  • 字单元:存放一个字型数据(16位)的内存单元,由两个地址连续的内存单元组成。高地址内存单元中存放字型数据的高位字节,低地址同理
  • 起始地址为N的字单元简称为N地址字单元
  • 8086CPU有一个DS寄存器,用来存放数据的段地址(CS存指令的段地址)
  • 指令格式:mov 寄存器 [内存单元地址],[]里面的是偏移地址,段地址此时从DS获取

栈(低地址存低位

  • CPU提供相关指令以栈的形式访问内存空间,这意味着可以将一段内存当作栈来使用
  • 8086CPU的入栈出栈操作都是以字为单位进行的
  • 8086CPU中,段寄存器SS存栈顶的段地址,寄存器SP存偏移地址。pop和push指令执行的时候,CPU从这两个寄存器获得栈顶地址
  • 栈的起始位置从底下开始,空栈时,栈顶指针指向栈的最底部单元的下一个单元
  • push和pop指令可以只给出内存单元的偏移地址,其余信息由DS,SS,SP寄存器给出
  • push和pop本质上就是内存传送指令,和move指令不同的是。move指令只需传送数据,而push和pop除此之外还要对栈顶指针操作
  • push先改变栈顶指针,再传输数据。pop先传输数据,再改变栈顶指针
  • 一个栈段最大容量为64KB(因为偏移地址就4位十六进制)

段的综述

可以将一段内存定义为段,段地址指示段,偏移地址访问段内单元。

数据段 代码段 栈段
DS:偏移地址 CS:IP SS:SP

CPU将某段内存当作代码,是因为CS:IP指向了那里;CPU将某段内存当作栈,是因为SS:SP指向了那里

预备知识:debug的使用

  • debug指令可以通过段寄存器给出段地址 如:d 段寄存器:偏移地址 (e,a,u指令同理)
  • debug的T命令在执行修改寄存器SS的指令时,下一条指令紧接着被执行(即按一次T执行两条指令),原因跟中断有关

第四章 第一个程序

知识点

  • 可执行文件包含两部分内容:程序和数据,相关描述信息

  • 操作系统依照可执文件中的描述信息,将可执行文件中的机器码和数据加载入内存,并进行相关初始化,(如设置CS:IP),然后由CPU执行程序

  • 汇编语言源程序中,包含两种指令:汇编指令和伪指令

  • 伪指令:编译器执行的指令,编译器根据伪指令进行相关编译工作.下面介绍三种常见的伪指令

    • segment和ends:这对伪指令的功能是定义段。一个段必须由一个名称标识。标识名称在编译,连接后处理为一个段的地址
    • end:和上面的ends不同,end是一个汇编程序的结束标记,编译器遇到后结束对文件的编译
    • assume 段寄存器:标识符:假设某一段寄存器与程序中某一个段相关联
  • 一个汇编程序由多个段组成,源程序中的指令,数据,栈被划分到了不同的段中

  • 用masm和link进行简化的手动编译和连接

    1."masm"后面+"源文件路径文件名;",按enter即可编译(不用加文件后缀名
    2."link"后面+"目标文件路径文件名;",按enter即可连接(不用加文件后缀名

  • 连接的作用:源程序很大时,可以分为多个源程序来编译,编译后由连接程序将它们连接到一起

  • 任何操作系统,都有一个shell(外壳)程序,用户通过这个程序操作计算机系统
    command.com是dos系统的shell, command执行用户输入的命令,将用户输入的程序加载入内存,设置CS:IP后,command停止运行,CPU运行程序

  • debug可以跟踪程序(如debug 1.exe):debug将程序加载入内存,设置CS:IP后,debug不放弃对CPU的控制,这样可以执行相关命令来单步执行程序
    单步执行的时候,执行INT指令的时候用P命令,其余用T
    command加载debug,debug加载要运行的程序,返回顺序相反

  • DOS系统中.exe文件中的程序所占内存分为两部分:PSP(称为程序前缀的数据区,DOS利用PSP和程序进行通信)和程序本身。其中PSP占前256字节。
    假设程序所在内存区的段地址是SA,则SA:0到SA+10H:0存PSP,其余存程序,程序段地址SA存在DS寄存器中

第五章 [BX]和loop指令

知识点

  • “()”表示一个寄存器或者一个内存单元中的内容
  • idata表示常量
  • inc bx的含义是bx中的内容+1

loop指令

  • CPU执行loop指令的时候,要进行两步操作
    1.(cx)=(cx)-1
    2.判断cx中的值,如果不为零则转至标号处执行程序,为零则向下执行

  • loop实现循环要点
    1.在cx中存放循环次数
    2.loop指令的标号所表示的地址要在前面
    3.要循环执行的程序段,要写在标号和loop指令的中间

  • 用loop实现循环的框架

    点击查看代码
     mov cx,循环次数
    
    s:
      循环执行的程序段
      loop s
    
  • 在汇编语言源程序中,数据不能以字母开头,所以要在前面+0

  • 在debug的时候,可以通过g指令跳过一些代码,起到断点的作用
    如:-g 0112 表示执行debug从当前CS:IP开始执行,到IP的值为0012为止

  • 当执行处于循环的代码时,使用p指令可以跳出循环


debug和汇编编译器masm对指令的不同处理

  • 现在编写汇编语言源程序有两种方法:

    1.在debug里用A指令写到内存中
    2.在masm里面编写
    

    不过两种方法对于类似于 mov al,[0]的指令有不同的解释。

    • debug将[]里面的0看作内存地址,将偏移地址为0的内容写入al
    • 而masm编译器将[0]看作0,将0写入al

    masm可以在[]前面加上"ds:",显式告诉编译器访问内存,段地址在ds中。如: mov al,ds:[0]

  • 这些出现在指令中,用于显式指明内存单元段地址的"ds:",在汇编语言中称为段前缀。(只有段寄存器才是段前缀!常用段寄存器:ds,cs,ss,es


  • 前面几章在debug编写源程序时,都是直接在某个内存中写入汇编指令的,但这很有可能修改重要的系统数据或代码,是不严谨的
    dos方式下,一般,0:200~0:2ff空间是没有数据和代码的,以后利用这段内存写入内容

第六章 包含多个段的程序

知识点

  • 上一章提到:不能随便更改内存内容。只有向操作系统申请取得的空间才是安全的。程序取得空间的方法有两种:

    • 加载程序时为程序分配。我们通过在源程序中定义段来进行内存空间的获取
    • 在程序执行时向系统申请
  • 在程序中,我们可以定义我们需要的数据,数据被编译连接后将成为可执行程序的一部分。
    可以用指令"dw 0123h,0789h"定义字型数据:define word,此时一个数据两字节

  • dw定义的数据,存放在程序地址的开头。存完这些数据之后才存汇编指令。

  • 如果开头dw定义了数据,那么内存地址的最开始不是我们要执行的指令,因此需要指出程序的真正入口(第一条汇编指令的地址),继而更改我们的CS:IP

    如下代码,end除了通知编译器程序结束之外,还可以通知编译器程序的入口在哪个地方。
    在编译连接后,end start指明的程序入口被转化为入口地址,存储在可执行文件的描述信息中(可执行文件由描述信息和程序组成)
    
    点击查看代码
    assume cs:code
    
    code segment
            数据
    start:
            代码
    code ends
    
    end start
    
  • 因此CS:IP变化过程为:程序加载后,由DS寄存器得到程序所在内存区的段地址,CS=DS+10H,IP偏移地址由可执行文件的描述信息指出,最终CS:IP指向第一条汇编指令所在的内存

  • dw定义的数据占有一定的内存空间,因此可以dw一系列0数据,来得到一块内存空间

  • 可以像定义代码段一样,通过segment和ends定义栈段,数据段,给个不同的段名就好

  • 一个段名代表一个段地址 ,段名被编译器处理为一个段地址数值。可以有:mov ax,段名 mov ds,ax ,但不能:mov ds,段名,因为8086不允许数值直接赋值给段寄存器,其他cpu可以


第七章 更灵活的定位内存地址的方法

知识点

and和or

  • and指令可以将位设0,or指令可以设1。想要设1或者设0,将对应位改成1或0即可。如:and al,01111111B即可将al的第七位设位0。or al,01000000B可以将第六位设为1

  • 大小写字母的ASCII码的二进制表示,除了第五位,其他都一样,因此可以用and和or指令进行大小写转化
  • 在汇编程序中,用'....'的方式指明数据是以字符的形式给出的,编译器将其转化为对应的ASCII码
  • si和di是和bx功能相近的寄存器
  • []里面可以放bx,si,di或者idata,均可以表示一个具体的内存单元的偏移地址
  • 当寄存器不够用,需要暂存数据时,可以将其暂存到栈中。

第八章 数据处理的两个基本问题

知识点

  • 寄存器汇总
    • reg表示寄存器,sreg表示段寄存器
      reg:ax,bx,cx,dx,sp,bp,di,si
      sreg:ds,cs,ss,es
  • 只有四个寄存器可以出现在[]里面来寻址:bx,si,di,bp
    • 这四个可以单独出现
    • 也可以以特定组合出现:bx和si,bx和di,bp和si,bp和di。(si或di必须跟随bx和dp中的一个
    • 只要[]里面有dp,若没有显式指出段寄存器,默认在ss中。(bx就默认段地址在ds中

寻址方式

  • 直接寻址:[idata]
  • 寄存器间接寻址:[bx],[si],[di],[dp]
  • 寄存器相对寻址:[bx+idata],[si+idata],[di+idata],[dp+idata]
  • 基址变址寻址:[bx+si],[bx+di],[dp+si],[dp+di]
  • 相对基址变址寻址:[bx+si+idata],[bx+di+idata],[dp+si+idata],[dp+di+idata]

  • 机器指令需要指出指令进行的是字操作还是字节操作,可以有三种方法指出
    • 通过寄存器指出处理数据的尺寸
    • 通过X ptr指明内存单元的长度,x可以是word或者byte。在没有寄存器参与的内存单元访问指令中,用X ptr显式指出要访问的长度是很有必要的
      如:mov byte ptr [1000H],1和mov word ptr [1000H]
    • 有些指令默认了访问的是字单元还是字节单元,如push和pop
  • 相对基址变址寻址[bx+si+idata]使得我们可以从结构化的角度看待要处理的数据,bx定位整个结构体,idata定位某个数据项,si定位数组项中的每个元素

除法指令div(需要用ptr指出要操作数据的大小

10/5=2,10是被除数,5是除数

  • 除数:在reg或内存单元中
  • 被除数:默认放在AX或者AX和DX中。如果除数为8位,被除数为16位,默认在AX中存放;如果除数为16位,被除数为32位,在DX和AX存放,DX放高位,AX放低位
  • 结果:如果除数为8位,AL存商,AH存余数;如果除数为16位,AX存商,DX存余数
  • 格式:div reg或者 div 内存单元

  • dd定义双字型数据,一个数据四字节
  • dup表示数据的重复:db 3 dup (0,1,2)定义了九字节,分别是0,1,2,0,1,2,0,1,2

第九章 转移指令的原理

知识点

  • 可以修改CS或者IP的指令成为转移指令
  • 转移指令分为
    • 段内转移:用目的地偏移地址修改IP。比如:"jmp ax" 其中,段内转移有分为短转移和近转移
      • 短转移:IP修改范围为-128-127
      • 近转移:IP修改范围为-32768-32767
    • 段间转移:用目的地段地址和偏移地址同时修改CS和IP,比如"jmp far ptr 标号""jmp 1000:0"
  • 操作符offset:获取标号的偏移地址 如:"mov ax,offset start"表示将start第一条指令的偏移地址存入ax
  • 一个转移指令需要指出目的地址,和转移的距离

  • 转移指令jmp后面可以跟:标号,寄存器,内存单元
  • jmp+寄存器在第二章已经见过了
  • "jmp short 标号"表示的是段内短转移,"jmp naer ptr 标号"表示的是段内近转移
    • 在一般的汇编指令中,idata立即数无论是表示数据还是内存单元的偏移地址,都会在机器指令中出现
    • 不过以上两种形式,jmp机器码没有给出目的地的偏移地址,编译器会计算出从jmp的下一条指令到标号的位移,将位移放入机器码
  • "jmp far ptr 标号"实现的是段间转移,机器码给出了目的地的段地址和偏移地址
  • jmp+内存单元有两种格式
    • "jmp word ptr 内存单元地址"(段内转移),内存单元地址处存放着一个字,是目的地的偏移地址
    • "jmp dword ptr 内存单元地址"(段间转移),内存单元地址存放着两个字,高地址处的字是目的地的段地址,低地址处是目的地的偏移地址
  • jcxc是条件转移指令,所以条件转移指令都是短转移,机器码中存放IP的位移
    • 指令格式:"jcxz 标号(如果cx=0,跳转到标号,否则什么也不做,继续往下执行
  • loop是循环指令,所以循环指令都是短转移,机器码存放IP的位移
    • 指令格式:"loop 标号"(cx--,如果cx=0,跳转到标号,否则什么也不做,继续往下执行

  • loop和jcxz两条指令跳转的条件正好相反!!!
  • jmp short 标号,jmp near ptr 标号,jcxz 标号,loop标号机器码都是存放IP的相对位移,而不是实际的地址,这样程序在内存的不同位置都可以正确执行
  • dec指令:和inc相反,dec bx表示bx--

关于jmp指令如何转化成机器码

  • 向前转移:即标号s在loop s前面出现
    • 计算位移,如果是-128-127,一律转变为jmp short s对应的机器码:EB disp(占两个字节);
    • 如果是-32768-32767,对于jmp short s将产生编译错误,对于jmp near ptr s和jmp far ptr s分别产生对应的机器码,E9 disp(三字节),EA 偏移地址 段地址(五字节
  • 向后位移,即loop s的时候标号s未出现,此时不能计算disp
    • 对于jmp short s,生成EB和一个nop指令
    • 对于jmp s和jmp near ptr s,生成EB和两个nop指令
    • 对于jmp far ptr s,生成EB和四个nop指令
      遇到标号s计算出disp时,再填充nop。如果disp属于-32768-32767,则对于jmp short s将产生编译错误

第十章 CALL和RET指令

知识点

  • "ret":利用栈中的数据修改IP的内容,等价于pop IP

  • "retf":利用栈中的数据修改CS和IP,等价于pop IP,pop CS

  • "call":将当前的IP或者CS和IP压入栈中,转移

    • "call 标号":等价于push IP,jmp near ptr 标号
    • "call far ptr 标号":段间转移,等价于push cs, push IP,jmp far ptr标号
    • "call 16位reg":等价于push IP,jmp 16位reg
    • "call word ptr 内存单元地址":等价于push IP,jmp wprd ptr内存单元地址
    • "call dword ptr 内存单元地址":等价于push CS,push IP,jmp dword ptr 内存单元地址
  • 可以用ret和call来实现调用子程序

    格式为
    标号:
        指令
        ret
    

mul指令

  • 两个相乘的数
    要么都是8位,要么都是16位

    • 如果是8位,一个默认在AL中,另一个放在内存或者8位reg
    • 如果是16位,一个默认在AX中,另一个在内存或者16位reg
  • 结果

    • 如果是8位,默认放在AX中
    • 如果是16位,高位在DX,低位在AX

子程序的标准框架
子程序开始:子程序中使用的寄存器入栈
           子程序内容
           子程序中使用的寄存器出栈;注意出栈入栈的顺序
           返回(ret,retf)

第十一章 标志寄存器

知识点

  • 标志寄存器有三种作用
    • 存储相关指令的执行结果
    • 用来为CPu执行相关指令提供行为依据
    • 用来控制CPU的相关工作方式
  • 标志寄存器flag存储的信息称为程序状态字
  • falg每一位都有专门的含义

标志位

  • ZF零标志位,相关指令执行结果为0,zf=1
  • PF奇偶标志位,如果结果所有bit位中1的个数是偶数,pf=1
  • SF符号标志位,如果结果为负,sf=1(对于有符号数才有意义
  • CF无符号运算的进位标,如果加法结果对更高位有进位值或者减法向更高位借位,cf=1
  • OF有符号运算的溢出标志位,如果发生溢出,of=1
  • DF方向标志位:在串处理指令中,控制每次si,di的增减
    • df=0,每次操作后si,di递增
    • df=1,每次操作后si,di递减

指令

  • adc带进位加法指令:"adc ax,bx"的功能是:(ax)=(ax)+(bx)+CF
    • 加法可以分两步进行,低位相加,高位相加再加上低位的进位
    • 因此,adc指令和add指令配合可以实现任意大的数据的加法
  • add和inc的区别在于,后者不改变CF的值
  • sbb带借位减法指令:"sbb ax,bx"的功能是:(ax)=(ax)-(bx)-CF
    • 利用sbb指令可以对任意大的数据进行减法,原理和adc一样
  • cmp比较指令:"cmp ax,bx"的功能是:计算ax-bx但并不保存结果,仅仅根据计算结果对标志寄存器进行设置
    • 对于有符号数(关注zf,cf)
      • zf判断ax,bx是否相等
      • cf=1,说明ax<bx
      • cf=0,说明ax≥bx
      • cf=0并且zf=0,说明ax>bx
      • zf=1或zf=1,说明ax≤bx
    • 对于无符号数(关注of,zf,sf)
      • 对于有符号数,如果溢出,sf的值判断结果正负是不正确的,因此还要关注of溢出位
      • 如果of有溢出,那么结果的正负和此时的sf是相反的。如果没有溢出,结果正负和sf正负相同

基于cmp比较结果的条件转移指令(以下是无符号数

  • je:等于则转移,zf=1
  • jne:不等于则转移,zf=0
  • jb:低于则转移,cf=1
  • jnb:不低于则转移,cf=0
  • ja:高于则转移,cf=0且zf=0
  • jna:不高于则转移,cf=1或zf=1

  • 其他操作也可能影响标志位,但是CPU并不关心逻辑含义,只要某位的条件满足,就发生转移
  • movsb串传送指令:将ds:si指向的内存单元的字节送入es:di中,然后根据df的值,将si和di递增或递减
  • movsw:将ds:si指向的内存单元的送入es:di中,然后根据df的值,将si和di递增2或递减2
  • rep:"rep movsb"等价于"s:movsb loop s",功能是根据cx的值,重复执行串传送指令,循环实现cx个字符的传送
  • 使用串传送指令时,需要给出一些必要的信息
    • 传送的原始位置ds:si
    • 传送的目的位置es:di
    • 传送的长度cx
    • 传送的方向df
  • cld:将falg的df设置为0
  • std:将flag的df设置为1
  • pushf和popf:将标志寄存器的值入栈or弹出数据,送入标志寄存器中

关于of和cf的判断

  • CF是无符号数关注的,如果最高位出现借位或者进位,cf为1
  • of是有符号数关注的,如果最高位和次高位异或为1(如果一个有进位,一个没有进位,就是溢出),代表溢出,of为1

第十二章内中断

知识点

  • 中断:CPU不再向下执行指令,而是转而处理中断信息
  • 中断处理程序:用来处理终端信息的程序,入口地址需要通过中断类型码获得
  • 中断信息可以来自CPU内部或者外部
  • 8086CPU有四个中断源
    • 除法错误 类型码:0
    • 单步执行 类型码:1
    • 执行into指令 类型码:4
    • 执行int指令 指令格式为int n,n就是类型码
  • 不同的中断信息对应不同的处理,8086CPU用一字节的中断类型码区分不同的中断信息
  • CPU通过类型码查中断向量表,从表中获取中断程序的入口地址
  • 中断向量表放在内存中,对于8086,0000:0000到0000:03FF的1024单元放向量表,一个入口地址两字,高位地址放段地址,低位放偏移地址
  • 中断过程:CPU硬件自动用中断类型码找到中断向量,并用它设置CS和IP。CPU收到中断信息后,首先引发中断过程,中断过程完成后,CS:IP指向程序入口,CPU再执行
    中断过程的具体步骤
    • 从中断信息中取得中断类型码
    • 标志寄存器入栈
    • 将flag的第八位TF和第九位IF值设为0
    • CS的内容入栈
    • IP的内容入栈
    • 找到入口地址,设置CS,IP
  • 编写中断处理程序
    • 保存要用到的寄存器
    • 处理中断
    • 恢复用到的寄存器
    • 用iret指令返回
  • 其中,iret指令等价于
    • pop IP pop CS popf
  • 编写中断程序的步骤
    • 编写中断程序的代码
    • 将中断程序送入内存(送到0000:0200到0000:02FF是向量表的一部分,但是一般没有那么多中断可以存
    • 更改向量表存着的中断程序地址
  • CPU执行完一个指令后,如果标志寄存器的TF位为1,则产生单步中断。进入中断处理程序。执行完中断处理程序的第一条指令,检测到TF为1,又产生单步中断进而造成死循环。所以中断过程需要将TF设为0
  • 有时候发生中断,CPU并不会响应,比如执行完向ss寄存器传送数据的指令后。因为ss和sp指向栈顶,对他们的设置应该连续完成

第十三章 int指令

知识点

  • int指令的格式为:int n,n为中断类型码。引发n号中断的中断进程
  • 中断进程:中断处理程序的简称
  • BIOS是在ROM存放的一个程序。BIOS和dos都提供了中断进程,BIOS主要包括以下部分
    • 硬件的检测和初始化程序
    • 外部,内部中断的中断例程
    • 用于对硬件设备进行IO操作的中断例程
    • 其他硬件系统相关的中断例程
  • BIOS和DOS中断例程的安装过程
    • 开机后,CPU一加电,初始化CS=0FFFFH,IP=0,FFFF:0有一个跳转指令,跳转到BIOS的硬件系统检测和初始化程序
    • 初始化程序将BIOS例程的入口地址都登记在中断向量表中
    • 硬件检测和初始化完成后,调用int 19h进行操作系统的引导,从此计算机由操作系统控制
    • DOS启动后,除了完成其他工作外,还将它所提供的中断例程装入内存,并建立相应的中断向量
  • 一个供程序员调用的中断例程包含多个子程序, 根据ah的参数来决定调用哪个子程序

四个中断例程的子程序

  • int 10h是BIOS提供的中断例程
    • 当ah=2时,子程序功能为:设置光标位置
      mov ah,2 设置光标位置功能
      mov bh,0 第0页
      mov dh,5 dh放行号
      mov dl,12 dl放列号
      int 10h
    • 当ah=9时,子程序功能为:在光标位置显示字符
      mov ah,9 在光标显示字符功能
      mov al,'a' 字符
      mov bl,7 颜色属性
      mov bh,0 第0页
      mov cx,3 字符重复个数
      int 10h
  • int 21h是DOS提供的中断例程
    • 当ah=4ch时,子程序功能为:程序返回功能
      mov ax,4c00h
      int 21h
    • 当ah=9时,子程序功能为:在光标位置显示字符串
      mov ax,data
      mov ds,ax
      mov dx,0 只要让ds:dx指向字符串首地址即可,显示的字符串后面要以字符'$'结尾
      mov ah,9
      int 21h

第十四章端口

知识点

  • CPU把各类存储器和芯片都当作一个总的逻辑存储器看待,称为内存地址空间
  • PC系统的接口卡和主板上,装有各种接口芯片。这些外设接口芯片的内部有若干寄存器,CPU将这些寄存器当作端口访问
  • CPU将端口进行统一编址,建立起端口地址空间,CPU通过端口地址访问端口
  • 端口的读写指令只有in和out
  • 在端口的读写指令中,只能使用ax或al来存放数据,访问8位用al,访问16位用ax

shl是逻辑左移指令,功能为:

  • 将寄存器或者内存单元的数据左移
  • 最后移除的一位写入CF中
  • 最低位用0填充
  • 如果移动的位数大于1,必须将移动位数放入cl中
    • mov al,00000001b
      mov cl,3
      shi al,cl

  • shr是逻辑右移指令,和shi相反,最高位用0填充

第十五章 外中断

知识点

  • CPu通过端口和外部设备进行联系
  • 当CPU外部有需要处理的事情发生时,相关芯片向CPu发出相应的中断信息。CPU执行完当前指令后,可以检测到1发送过来的中断信息,引发中断过程

两类外中断源

  • 可屏蔽中断
    • 当CPU检测到中断信息时,如果flag中的IF=1,CPU 执行完当前指令后执行中断例程,如果IF=0,则不响应可屏蔽中断
    • 中断过程中将IF置0的原因是:在进入中断例程后,禁止其他可屏蔽中断
  • 不可屏蔽中断
    • 不可屏蔽是CPU执行完当前指令,必须响应的中断
    • 对于8086CPU, 不可屏蔽中断的类型码固定为2

PC键盘机的处理

  • 按下松开键时,键盘中的芯片产生对应的扫描码,扫描码将送入端口,该端口地址为60h按下时产生通码,送开时产生断码,断码=通码+80h
  • 当键盘的输入到达60h端口时,相关芯片向CPU发出中断类型码为9的可屏蔽中断。若IF为1,则响应中断
  • BIOS提供的int 9中断例程主要工作如下:
    • 读出60h端口的扫描码
    • 如果是字符键的扫描码,将扫描码和对应的ASCII送入内存中的BIOS键盘缓冲区;如果是控制键和切换键的扫描码,则将其转化为状态字节,写入内存中存储状态字节的单元
    • 对键盘系统进行相关控制,比如向芯片发出应答信息
  • BIOS键盘缓冲区是用于存放int 9h中断例程所接收的键盘输入的内存区,最多存储15个键盘输入,一个键盘输入用一个字单元存放,高位扫描码,低位字符码
  • 0040:17单元存储键盘状态字节,每一位都有特定含义

第十六章 直接定址表

知识点

  • 数据标号:标记了存储数据的单元的地址和长度,在指令中可以代表一个内存单元
  • 后面加有“:”的标号,只能在代码段中出现
  • 想要直接用数据标号访问数据,需要使用伪指令assume将标号所在的段地址和一个段寄存器联系起来,程序中也需要用指令将段寄存器联系起来
  • 可以像定义数据一样定义标号。如果用dw定义标号,则存储的值是标号的偏移地址;如果用dd定义标号,则存储的值是段地址和偏移地址
  • seg 标号:获取标号的段地址
  • 直接定址表:一种编程技巧?将需要的东西事先存在表里,以后用数据查表即可高效完成任务,空间换时间

第十七章 使用BIOS进行键盘输入和磁盘读写

  • 键盘缓冲区使用循环队列实现的
  • 键盘输入的过程
    • 按下按键,引发9号中断
    • 从60h端口读出键的通码
    • 检查状态字节,是否有shift或者ctrl按下
    • 根据状态字节将正确的ASCII码和扫描码存入缓冲区。低位存储ASCII,高位扫描码
  • 字符串的存储空间实际上是一个字符栈
  • BIOS提供了中断例程int 13h中的2号子程序来方便程序员访问磁盘
posted @   穿过雾的阴霾  阅读(112)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示