汇编语言(第三版) 王爽 读书笔记

前言:书终于看完了,在这里做一下笔记,以备忘,也与大家分享知识,第一次在CSDN上写博客,如有不足还望大家多多指正,欢迎大家在下面留言讨论!

写在前面:①  想要零基础学汇编的朋友可以看这里,在这里我强烈向大家推荐王爽老师的这本《汇编语言》,真的写的非常好,思路清晰,通俗易懂,知识循序渐进,每章都有小习题、实验(还有提醒一定要完成实验,非常贴心),可以说是非常好了。

下面我要介绍的汇编语言主要是基于16位8086CPU 的,(注:汇编语言是机器相关的,而且Inter和AT&T的汇编语言语法是不同的),然后是在XP系统上做的实验,汇编器用的MASM5.0

声明:本文中部分截图取自王爽老师的《汇编语言》,当然有些内容也是抄自此书

正文:

学习汇编主要就是学习寄存器和指令的使用,当然还有用于汇编器识别的伪指令等。本文以寄存器和指令为两大主线整理,主要是用于存储知识。

汇编相关知识:

在debug中查看内存单元中的内容时都是以16进制显示的,在程序中,数默认是十进制的,在数后面加h表示为16进制,用16进制时要注意不能以字母开头表示数,如:f000h这样直接写的话是错的,应该这样写0f000h.

debug中的一些命令简介:

r:查看、改变CPU寄存器的内容

d:查看内存中的内容

e:改写内存中的内容

u:将内存中的内容解释为机器指令和对应的汇编指令

t:执行cs:ip指向的内存单元处的指令

a:以汇编指令的形式向内存中写入指令

g:一直执行指令到指定内存单元

p:直接完成子程序或中断的调用,在debug中当要执行int 21h时一定要用p命令使程序正常退出

q:退出debug模式

80×25彩色字符显示模式显示缓冲区结构如下:

内存地址空间中,b800h~bffffh共32KB的空间,为80×25彩色字符模式的显示缓冲区。向这个地址空间写入数据,写入的内容将立即出现在显示器上。

80×25彩色字符模式下,显示器可以显示25行,每行80个字符,每个字符可以有256种属性(背景色、前景色、闪烁、高亮等组合信息,注意:闪烁效果只有在全屏DOS下才看的到效果)。

其中一个字符在显示缓冲区就要占两个字节,高位放属性,低位放ASCII码。在80×25模式下,一屏的内容在显示缓冲区中共占4000个字节。

显示缓冲区分为8页,每页4KB(≈4000B),显示器可以显示任意一页的内容,一般显示第0页的内容,也就是说,通常情况下b800h~bffffh中的内容会出现在显示器上。


④直接定址表中用到的数据标号简介,数据标号地址:汇编器实际将该标号翻译成其所在段中的偏移地址。在使用数据标号时,要用assume将所在段与一个sreg关联起来,并且在程序中使用前要把该段的段地址存入关联的sreg中,不然程序将发生错误。

标号的唯一功能是标识,其偏移地址还要通过offset来获取;而数据标号有很多功能,它本身就可以表示其在所在段中的偏移地址,它还包含了单元的大小信息。例:数据标号 s db 1,2,3;标号 k: db 1,2,3

寄存器部分:

8086有14个寄存器ax,bx,cx,dx,si,di,sp,bp,ip,cs,ss,ds,es,psw

分类:

通用寄存器:ax   bx   cx   dx

段地址寄存器:es   cs   ss    ds

指令指针寄存器:ip

其他寄存器:bx   di   si   bp 可用于间接寻址的寄存器

                       psw (标志寄存器)

                       sp (用于栈的寄存器)

通用寄存器介绍:

通用寄存器主要用途是存储数据,或做数据中转站,当然还有一些其他的特殊用途,因为计算机里面的寄存器数量实在是太有限。

每个通用寄存器都是16位的,并且都可以分为两个8位的子寄存器:

ah   al   bh   bl   ch   cl   dh   dl

其中后面带h的代表是高8位,带l的代表低8位。如:ah为ax的高8位,al为ax的低8位

ax&dx:

ax和dx用法基本相同,特殊用途也基本一致,其主要用途体现在div(除法指令)和mul(乘法指令)中;不过ax还有一个特殊的用途就是,用in和out读写时,只能用al或ax存储数据。

in & out:

端口的读写指令只有两条:in和out,分别用于从端口读取数据和往端口写入数据。

注意:在in和out指令中,只能使用al或ax来存放从端口中读入的数据或要发送到端口的数据。访问8位端口时用al,访问16位端口时用ax。(端口相关知识请看后面)

对0~255以内的端口进行读写时,端口号为一个立即数:

    in al,20h

    out 20h,al

对256~65535的端口进行读写时,端口号放在dx中:

    mov dx,3f8h

    in al,dx

    out dx,al

div:

格式:

   div reg

   div 内存单元

除数:有8位和16位两种,在一个reg或内存单元中

被除数:默认放在ax或dx和ax中,如果除数为8位,被除数则为16位,默认在ax中;如果除数为16位,则被除数为32位,在dx和ax中存放,dx存放高16位,ax存放低16位

结果:如果除数为8位,则al存储除法操作的商,ah存储除法操作的余数;如果除数为16位,则ax存储除法操作的商,dx存储除法操作的余数

(使用div时要注意可能会溢出,例如:ax=0000h,dx=0fh,bx=1h,则div bx 将发生溢出,因为ax存不下0f0000h。解决办法就是自己写一个不溢出的除法子程序)

mul:

格式:

   mul reg

   mul 内存单元

两个相乘的数:两个相乘的数要么都是8位,要么都是16位。如果是8位,一个默认放在al中,另一个放在8位reg或内存字节单元中;如果是16位,一个默认在ax中,另一个放在16位reg或内存字单元中。

结果:如果是8位乘法,结果默认放在ax中;如果是16位乘法,结果高位默认在dx中存放,低位在ax中。

(mul应该也有溢出现象吧,没验证过)

bx:

bx的特殊功能主要就是像bp,si,di一样能用在[...]中来进行间接寻址,

其中[bx],[si],[di]默认段地址都是ds,而[bp]的默认段地址是ss。

如果在[...]前面指定了段地址,那就是指定的段地址了

正确用法:

mov ax,[bx] [si] [di] [bp]

mov ax,[bx+idata] [si+idata] [di+idata] [bp+idata]

mov ax,[bx+si] [bx+di] [bp+si] [bp+di]

mov  ax,[bx+si+idata] [bx+di+idata]

mov ax,[bp+si+idata] [bp+si+idata]   (注:idata表示一个数,1,2,3等等)

错误用法:

mov ax,[bx+bp]

mov ax,[si+di]

···这里顺便介绍一下间接寻址方式:

一般用es,ds做段地址寄存器(sreg)

主要形式可参考上面的,不带段寄存器的形式[...],带段寄存器的形式sreg:[...],注意没有这样的形式[idata],这是错误的。然后关于idata还有一些特殊的用法:

[bx+idata]等价于idata[bx] 或 [bx]idata,前面相当于属结构体形式,后面相当于数组形式(细细体会)

其余形式类推

cx:

cx特殊用途主要是与指令jcxz,loop,rep movsb配合使用,作他们的判定条件;还有一个特殊的用途是做指令shl和shr的移动位数。

jcxz:

jcxz指令为有条件跳转指令,所有的有条件指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址。对IP的修改范围为:-128~127

指令格式:jcxz 标号 (如果(cx)=0,转移到标号处执行)

操作:当(cx)=0时,(IP)=(IP)+8位移 ;当(cx)≠0时,程序向下执行

8位位移 = 标号处的地址 - jcxz指令后的第一位字节地址;

8位位移的范围为-128~127,用补码表示;

8位位移由编译程序在编译时算出。

loop:

loop指令为循环指令,所有的有循环指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址。对IP的修改范围为:-128~127

指令格式:loop 标号 ((cx)=(cx)-1,如果(cx)0,转移到标号处执行)

操作:⑴ (cx)=(cx)-1

          ⑵ 如果(cx)≠0,(IP)=(IP)+8位位移 ;如果(cx)=0,程序向下执行

(注意执行loop指令时,先做cx-1然后在判断cx是否为0,所以用cx做循环次数时,直接把要循环的次数赋给cx就行了,循环就是cx次了,因为在loop执行之前已经做了一次了)

8位位移 = 标号处的地址 - loop指令后的第一位字节地址;

8位位移的范围为-128~127,用补码表示;

8位位移由编译程序在编译时算出。

rep movsb:

movsb指令,将以ds:si指向的内存单元中的字节送到es:di中,然后根据标志寄存器df位的值,将si和di递增或递减。(movsb指令只做一次 )

rep的作用是根据cx的值,重复执行后面的串传送指令

同类指令:movsw  一次复制的是字单元

rep movsb配合起来使用才是一条完整的传送指令,将原始位置ds:si的cx个字节复制给以es:di为起始地址的cx个字节单元中。其功能相当于:

s:movsb

   loop s

由于标志寄存器的df位决定了传输的方向,我们一般用下面的指令来改变标志位df:

cld指令: 将标志寄存器的df位置0

std指令:将标志寄存器的df位置1

shl & shr:

shl和shr是逻辑位移指令,其中shl是逻辑左移指令,shr是逻辑左移指令。

shl功能为:

(1)将一个寄存器或内存单元中的数据向左移位;

(2)将最后移出的一位写入cf中;

(3)最低位用0补充。

shr功能为:

(1)将一个寄存器或内存单元中的数据向右移位;

(2)将最后移出的一位写入cf中;

(3)最高位用0补充。

如果移动位数大于1时,必须将移动位数放在cl中;若移动位数为1,可以直接这样写,例:shr ax,1

段寄存器简介:

段寄存器有四个:cs   ss    es   ds

主要能用的就是es,ds,没有什么好介绍的额(手动滑稽)

寄存器组合应用介绍:

组合cs:ip:表示当前执行的指令所在的地址,一般无法直接改变,通过跳转指令可以改变,跳转指令后面介绍。

组合ss:sp:这两个寄存器一般用做栈,栈顶的段地址存放在ss中,偏移地址存放在sp中,任意时刻,ss:sp指向栈顶元素。

提到栈就必须得提到push指令,pop指令还有pushf指令和popf指令

push & pop:

指令格式:

push 寄存器    ;将一个寄存器中的数据入栈

pop 寄存器     ;出栈,用一个寄存器接收出栈的数据

push 段寄存器    ;将一个段寄存器中的数据入栈

pop 段寄存器     ;出栈,用一个段寄存器接收出栈数据

push 内存地址    ;将一个内存单元出的字入栈(注意:栈操作都是以字为单元)

pop 内存单元     ;出栈,用一个内存字单元接收出栈的数据

push操作:

(1)sp=sp-2,ss:sp指向当前栈顶前面的元素,以当前栈顶前面的单元为新的栈顶;

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


pop操作:(与push的正好相反)

(1)将ss:sp指向的内存单元处的数据送入ax中;

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

(注意:pop操作结束后,相应单元里面的内容并没有被删除,依然存在,只是sp移动了)

【注意】汇编语言中push和pop对栈越界是没有检测和处理的,只能程序员自己在使用时注意不让程序发生栈越界,因为超界是非常危险的。

段寄存器ss还有一个值得注意的细节时:在debug调试中,执行完mov ss,reg(即向ss中移入数据)后会顺带执行其后面一条指令。

pushf & popf:

pushf和popf相当于特殊的push和pop指令,pushf指令的功能是把状态寄存器压入栈,而popf指令的功能是将状态寄存器出栈(注意:状态寄存器其实和ax等普通寄存器一样,都是16位,只是它的每个位有特殊含义而已)

最特殊的寄存器---状态寄存器

状态寄存器(以下简称flag)中存储的信息通常被称为程序状态字(PSW),flag主要有以下3种功能:

(1)用来存储相关指令的某些执行结果;

(2)用来为CPU执行相关指令提供行为依据;

(3)用来控制CPU的相关工作方式。

其结构如下图:


其中1、3、5、12、13、14、15位是没有使用的,不具有任何特殊含义,其余位都有特殊含义。

下面介绍各个标志位代表的含义:

ZF(零标志位):它记录相关指令执行后,其结果是否为0。如果结果为0,则zf=1;如果结果不为0,那么zf=0。

PF(奇偶标志位):它记录相关指令执行后,其结果的所有bit位中1的个数是否为偶数。如果1的个数为偶数,pf=1;如果为奇数,pf=0。

SF(符号标志位):它记录相关指令执行后,其结果是否为负。如果结果为负,sf=1;如果非负,sf=0。

CF(进位标志位):一般情况下,在进行无符号数运算的时候,它记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值。

OF:of与cf类似,都是进位标志位,只不过of针对的是有符号数运算时的进位或借位信号。

Df(方向标志位):在串处理指令中,控制每次操作后si、di的增减。

   df=0 每次操作后si、di递增;

   df=0 每次操作后si、di递减。(前面介绍过一部分内容)

cld & std:

cld指令置DF为0;std指令置DF为1。

sti & cli:

sti指令置IF为1;std指令置IF为0。

指令部分:

伪指令及操作符介绍:

offset:操作符offset是由汇编器处理的符号,格式为:offset 标号,功能:取得标号的偏移地址

assume:格式:assume sreg:段标号。例:assume cs:code    ;将段code与cs关联起来

;:;为汇编里面的注释格式,后面跟注释内容,只能管一行,相当于c语言中的//

dd & dw & dd:db,dw,dd来定义字节型数据,字型数据和双字型数据,例:dd 0,2,4,5.'a'

dup: dup是一个操作符,它是和db,dw,dd配合使用,用来进行数据的重复,例:dd 3 dup (0),定义3个字节,值都为0,相当于db 0,0,0

org: org伪指令的功能设定其后面指令的偏移地址,例:org 200h功能是,其后指令的偏移地址从200h开始

汇编指令分类:

1.数据传输指令:mov、push、pop、pushf、popf、xchg等,这些指令对标志寄存器没有影响

2.算术运算指令:add、sub、adc、sbb、inc、dec、cmp、imul、idiv、aaa等,它们的执行结果将影响标志寄存器的sf、zf、of、cf、pf、af位。

3.逻辑指令:and、or、not、xor、test、shl、shr、sal、sar、rol、ror、rcl、rcr等,除了not指令外,它们的执行结果都影响标志寄存器的相关标志位。

4.转移指令:可以修改ip,或同时修改cs和ip的指令统称为转移指令。转移指令又分一下几类:

(1)无条件转移指令:jmp

(2)条件转移指令:jcxz、je、jb、ja、jna、jnb等

(3)循环指令:loop

(4)过程:call、ret、retf

(5)中断:int、iret

5.处理机控制指令:cld、std、cli、sti、nop、clc、cmc、stc、hlt、wait、esc、lock等,这些指令对标志寄存器或其他处理机状态进行设置。

6.串处理指令:movsb、movsw、cmps、scas、lods、stos等,若要使用这些指令方便的进行批量数据的处理,则需要和rep、repe、repne等前缀指令配合使用。

mov:

mov指令有两个操作对象,其功能是将第二个操作对象的值赋给第一个操作对象。

指令格式:

mov reg,数据    mov reg,sreg    mov sreg,reg    mov reg,reg    mov reg,内存单元   

mov 内存单元,reg    mov sreg,内存单元    mov 内存地址,sreg

这里顺便介绍一下经常与mov配合使用的伪指令byte ptr(表示进行字节操作)、word ptr(表示进行字操作)和dword ptr(表示进行双字操作,及32位操作,一般在转跳指令中才用的到)

例:mov byte ptr [bx],al    ;进行字节操作,将al中一个字节的内容存入地址ds:[bx]一个字节大小的单元中

mov word ptr [bx],ax    ;进行字操作,将ax中一个字的内容存入地址ds:[bx]一个字大小的单元中

【注意】这样的指令时错误的{ mov sreg,数据    mov sreg,标号    mov sreg,sreg    mov 内存单元,内存单元 }段寄存器和数据之间 ,段寄存器和标号之间,段寄存器之间,内存单元之间不能直接赋值,要通过普通寄存器做中介来完成赋值操作。

add & sub:

这两个指令非常相似,都有两个操作对象,操作结果都赋给第一个操作对象。add指令进行的是加法操作,结果赋给第一个操作对象;sub指令进行的是减法操作,第一个操作对象减第二个操作对象,结果赋给第一个操作对象。

指令格式:

add reg,数据    add reg,reg    add reg,内存单元    add 内存单元,reg

sub reg,数据    sub reg,reg     sub reg,内存单元    sub 内存单元,reg

【注意】add sreg,reg这样的指令时错误的,段寄存器和寄存器之间是不能相加减的

介绍完add和sub,在介绍与他们相关的四个指令inc和dec,adc和sbb

inc & dec:

这两个指令的操作数都只有一个操作对象,操作数可以是16位的,也可以是8位的,inc的功能是将操作数+1,dec的功能是将操作数-1。

例:inc ax    ;将ax加1,与add ax,1功能一样,但效率更高

      dec ax    ;将ax减1,与sub ax,1功能一样

adc & sbb:

这两个指令和add,sub类似,但adc和sbb多了一个隐式的操作数cf,因为他们是要用到标志寄存器相关位的指令

adc是带进位加法指令,它利用了cf上记录的进位值

指令格式:adc 操作对象1,操作对象2

功能:操作对象1 = 操作对象1 + 操作对象2 +cf

例如指令adc ax,bx实现的功能为:(ax) = (ax) + (bx) +cf

sbb是带借位减法指令,它利用了cf上记录的借位值

指令格式:sbb 操作对象1,操作对象2

功能:操作对象1 = 操作对象1 - 操作对象2 -cf

例如指令sbb ax,bx实现的功能为:(ax) = (ax) - (bx) -cf 

【注意】这两个要用到标志位cf,但我们怎样才能知道cf的值了,实际上标志位的值只能有程序员自己把控,没有显视的显示方法,当需要什么值时要自己设定。一般情况下,adc指令和sbb指令都用来做加法或减法的功能扩展,一般adc指令都跟在add指令或adc指令后,而sbb指令跟在sub或sbb指令后,这个时候程序员应该自己把控add指令或sub指令执行后标志位cf的值,然后来写程序。

cmp:

cmp是比较指令,其功能相当于减法指令,只是不保存结果,cmp指令执行后,将对标志寄存器产生影响,其他相关指令通过识别这些被影响的标志寄存器为来得知比较结果。

指令格式:cmp 操作对象1,操作对象2

功能:计算操作对象1-操作对象2 但并不保存结果,仅仅根据计算结果对标志寄存器进行设置。

以cmp ax,bx为例(无符号数运算):

若(ax)=(bx),则(ax)-(bx)=0,zf=1

若(ax)≠(bx),则(ax)-(bx)≠0,zf=1

若(ax)<(bx),则(ax)-(bx)将产生借位,cf=1

若(ax)≥(bx),则(ax)-(bx)不必借位,cf=0

若(ax)>(bx),则(ax)-(bx)既不必借位,结果又不为0,所以cf=0且zf=0

若(ax)≤(bx),则(ax)-(bx)既可能借位,结果可能为0,所以cf=0或zf=0

cmp在进行有符号数运算时由于要考虑溢出情况,分析将变得复杂起来,下面以cmp ah,bh为例,讨论进行有符号数运算时,对标志寄存器位的影响:

若sf=1,of=0,无溢出,则(ah)<(bh)

若sf=1,of=1,of=1说明有溢出,导致实际结果为负,则逻辑上的结果为正,所以(ah)>(bh)

若sf=0,of=1,of=1说明有溢出,导致实际结果为正,则逻辑上的结果为负,所以(ah)<(bh)

若sf=0,0f=0,无溢出,则(ah)≥(bh)

and & or:

and指令:逻辑与指令,按位进行与运算。

or指令:逻辑或指令,按位进行或运算。

例:mov al,01100011b

and al,00111011b    ;执行后:al=00100011b

mov al,01100011b

or  al,00111011b     ;执行后:al=01111011b

这里介绍一下and和or指令在字符处理时最常用且最高效的用法:

al里存的是英文字母a~z,或A~Z的ASCII码

and al,11011111b    ;将字符变大写

or al,00100000b    ;将字符变小写

接下里就是非常重要的内容---跳转指令的介绍了:

jcxz指令和loop指令前面介绍过,这里不再赘述。值得注意的一点是,由于转移范围受到转移位移的限制,如果在源程序中出现了转移范围超界的问题,在编译的时候,编译器将报错

jmp:

jmp为无条件跳转指令,可以只修改ip,也可以同时修改cs和ip的值。

jmp指令要给出两种信息:(1)转移的目的地址(2)转移的距离(段间转移、段内短转移、段内近转移)

CPU在执行jmp指令时并不需要转移的目的地址,实际上是通过偏移地址来工作的。

①依据位移进行转移的jmp指令:

    jmp short 标号   (转到标号处执行指令)

    jmp near ptr 标号 (此指令实现的是段内近转移,功能为:(ip)=(ip)+16位位移;16位移=标号处的地址-jmp指令后的第一个字节的地址,用补码表示;near ptr指明此处位移为16位位移)

②转移目的地址在指令中的jmp指令:

    jmp far ptr 标号    ;此指令实现的是段间转移,又称为远转移

    (cs)=标号所在段的段地址;(ip)=标号在段中的偏移地址

③转移地址在寄存器中的jmp指令:

    指令格式:jmp 16位寄存器

    功能:(ip)=(16位reg)    ;注意:只修改ip的值

④转移地址在内存中的jmp指令:

    1.jmp word ptr 内存单元地址(段内转移)

    功能:从内存单元地址处开始存放着一个字,是转移的目的偏移地址

    2.jmp dword ptr 内存单元地址(段内转移)

    功能:从内存单元处开始存放着两个字,高地址处的字是转移的目的段地址,低地址处是转移的目的偏移地址

call & ret:

call指令和ret指令经常配合使用,以实现子程序的调用,通常用法是用call指令将当前cs:ip值保存在栈中,可理解为保护现场,然后跳转执行子程序,一般子程序最后一条指令一定是ret或retf,将栈中数据出栈,修改cs:ip的值,返回主程序。

ret指令用栈中的数据,修改ip的内容,相当于pop ip,从而实现近转移;

retf指令用栈中的数据,修改cs和ip的内容,相当于pop ip,pop cs,从而实现远转移。

ret指令操作:

(1)(ip)=((ss)*16+sp)

(2)(sp)=(sp)+2

retf指令操作:

(1)(ip)=((ss)*16+sp)

(2)(sp)=(sp)+2

(3)(cs)=((ss)*16+sp)

(4)(sp)=(sp)+2

call指令不能实现短转移,除此之外,call指令实现转移的方法和jmp指令的原理相同,具体参考jmp指令,这里不再赘述。

call指令操作:

(1)将当前的ip或cs和ip压入栈中    ;相当于pop ip或pop cs,pop ip

(2)转移    ;相当于jmp

中断、端口、BIOS简介:

中断:

任何一个通用的CPU都具备一种能力,可以在执行完当前正在执行的指令之后,检测到从CPU外部发送过来的或内部产生的一种特殊信息,并且可以立即对所受到的信息进行处理。这种特殊的信息,称之为:中断信息。

8086CPU用称为中断类型码的数据来标识中断信息的来源,中断类型码为一个字节型数据,可以表示256种中断类型来源。

中断过程:用中断类型码找到中断向量,并用它设置cs和ip,这个工作由CPU的硬件自动完成。CPU硬件完成这个工作的过程就叫做中断过程。其主要操作如下:

    1.取得中断类型码N;

    2.pushf

    3.TF=0,IF=0

    4.push cs

    5.push ip

    6.(ip)=(n*4),(cs)=(n*4+2)

CPU处理中断的过程:首先接收中断类型码,然后根据中断类型码在中断向量表中查找中断处理程序的入口地址,然后根据地址跳转,执行中断处理程序。

中断向量表就是中断处理程序的入口地址的列表,每个表项占两个字,高地址字存放段地址,低地址字存放偏移地址。内存0:0~0:3ff,大小为1KB的空间是系统存放中断处理程序入口地址的中断向量表。不过实际上,系统要处理的中断事件远没有达到256个,中断向量表中有许多空间是空的。一般中断向量表从0:200到0:2ff的256个字节的空间所对应的中断向量表项都是空的,我们可以在在这里开始存放我们的中断处理程序或中断处理程序入口地址。

内中断:来自CPU内部的中断信息。当CPU内部有下面情况发生时,将产生相应的中断信息:

(1)除法错误    ;中断类型码为0

(2)单步执行(一般debug模式下)    ;~为1

(3)进行into指令    ;~为4

(4)执行int指令    ;该指令格式为int n,n为字节型立即数,是提供给CPU的中断类型码

外中断:来自CPU外部的中断信息。例如:当外设的输入到达时,相关芯片将向CPU发出相应的中断信息。引发外中断的外中断源一共有以下两大类:

(1)可屏蔽中断:顾名思义,CPU可以不响应此类中断。当CPU检测到可屏蔽中断信息时,如果IF=1,则CPU在执行完当前指令后响应中断;如果IF=0,则不响应可屏蔽中断。

(2)不可屏蔽中断:CPU必须处理的中断,对8086CPU,不可屏蔽中断的中断类型码固定为2

提到中断,就提到nt和iret指令,下面来介绍着两个指令。

int & iret:

int指令格式:int n,n为中断类型码

功能:引发中断过程

过程:

(1)取中断类型码n

(2)标志寄存器入栈,IF=0,TF=0

(3)cs、ip入栈

(4)(ip)=(n*4),(cs)=(n*4+2)    ;可见int指令的最终功能和call指令相似,都是调用一段程序

iret指令与ret指令雷士,其操作等价于:pop ip,pop cs,popf

端口:

在PC机系统中,和CPU通过总线相连的芯片除了各种存储器外,还有以下三种芯片:

(1)各种接口卡(比如,网卡、显卡)上的接口芯片,它们控制接口卡进行工作

(2)主板上的接口芯片,CPU通过他们对外部外设进行访问

(3)其他芯片,用来存储相关的系统信息,或进行相关的输入输出处理

在这些芯片中,都有一组可以有CPU读写的寄存器,CPU将这些寄存器都当做端口,对它们进行统一编址,从而建立了一个统一的端口地址空间,每个端口在地址空间中都有一个地址。对端口的读写指令只有两条:in和out,分别用于从端口读取数据和往端口写入数据。

BIOS:

在系统板的ROM中存放着一套程序,成为BIOS(基本输入输出系统),BIOS中主要包含以下部分内容:

(1)硬件系统的检测和初始化程序;

(2)外部中断和内部中断的中断例程:

(3)用于对硬件设备进行I/O操作的中断例程;、

(4)其他和硬件系统相关的中断例程。

(操作系统DOS也提供了中断例程,这些例程同时也是很好的工具)

开机后,CPU自动进入到ffff:0单元处执行,此处有一条跳转指令,CPU执行该指令后,转去执行BIOS中的硬件系统检测和初始化程序。初始化程序将建立BIOS所支持的中断向量,即将BIOS提供的中断例程的入口地址登记在中断向量表中。

硬件系统检测和初始化完成后,调用int 19h进行操作系统的引导。

如果设为从软盘启动操作系统,则int 19h将主要完成以下工作:

(1)控制0号软驱,读取软盘0道0面1扇区的内容到0:7c00h

(2)将cs:ip指向0:7c00h

软盘的0道0面1扇区中装有操作系统引导程序。int 19h将其装到0:7c00h处后,设置CPU从0:7c00h开始执行此处的引导程序,操作系统被激活,控制计算机。如果在0号软驱中没有软盘,或发生软盘I/O错误,则int 19h将完成以下主要任务:

(1)读取硬盘C的0道0面1扇区的内容到0:7c00h

(2)将cs:ip指向0:7c00h

其他硬件相关知识:

具体的硬件知识太繁杂,这里只是将书中提到的一些知识列出来,并不做深入的讨论与讲解,如果要了解详情的,请自行到网上查找相关资料。

int 10h中断例程有设置光标位置的功能;

PC机中,有一个CMOS RAM芯片,里面有一个实时钟和一个有一个128个存储单元的RAM存储器,具体上网。

PC机键盘的处理过程;

int 9h中断例程提供基本的键盘输入处理;

键盘缓冲区相关知识;

int 16h中断例程可以读取键盘缓冲区;

磁盘读写相关知识,及int 13h中断例程可以对磁盘进行读取;


最后BB一下,终于写完了,真累啊,写了这么多字,还用了很多时间,希望以后能发挥作用,不要辜负了我付出的时间(手动滑稽得意











猜你喜欢

转载自blog.csdn.net/Anthony_XL/article/details/80541477