汇编语言(2)程序表示
第四章 第一个程序
39.源程序从写出到执行的过程:
(1)编写汇编源程序
(2)对源程序进行编译连接(生成可在操作系统直接运行的可执行文件)
可执行文件包含:<1>程序(机器码)和数据。<2>相关描述信息(程序多大,占多少空间)
(3)执行可执行文件中的程序。
40.伪指令:
(1)XXX segment
...
...
XXX ends
其中XXX是段名。segment说明一个段开始 ,ends说明一个段结束(他们都是编译器执行)。
(2)end: 汇编程序结束的标志。编译器在编译汇编过程中,碰到end就结束对源程序的编译。
(3)Assume:假设 。它假设某一段寄存器和程序中的某一个用 segment...ends定义的段相关联(将有特定用途的段和想关的段寄存器关联起来)。
41.标号:一个标号指代了一个地址。比如codesg在segment的前面,作为一个段的名称,这个段的名称最终将被编译、连接程序处理为一个段的地址段。
42.一个程序结束后,将CPU的控制权交还给使它得以运行的程序,这个过程就是程序返回,程序返回需要两个指令(由CPU执行):
mov ax,4c00H
int 21H
43.连接的作用:
(1)当源程序很大时,可以将它分为多个源程序文件来编译,每个源程序编译称为目标文件后,再用连接程序将他们连接到一起,生成一个可执行文件。
(2)程序中调用了某个库文件中的子程序,需要将这个库文件和该程序生成的目标文件连接到一起,生成一个可执行文件。
(3)一个源程序编译后,得到了存有机器码的目标文件,目标文件中的有些内容还不能直接用来生成可执行文件,连接程序将这些内容处理为最终的可执行信息。所以,在只有一个源程序文件,而又不需要调用某个库中的子程序的情况下,也必须用连接程序对目标文件进行处理,生成可执行文件。
44.[bx]同样表示一个内存单元,它的偏移地址在bx中。
45.注:使用描述性符号()来表示一个寄存器或一个内存单元中的内容,比如(ax)表示 ax中的内容。()中的元素可以有三种类型:寄存器名,段寄存器名,内存单元的物理地址(一个20位数据)。 (X)表示的数据有两种类型:字节和字。具体类型由寄存器名或具体的运算决定。比如: (al) (bl)(cl)等得到的数据为字节型; (ds)(ax)(bx)等得到的数据为字型。
46.符号 idata表示常量。
47.Loop指令: loop 标号;CPU执行loop指令的时候,要进行两步操作:1.(cx) = (cx) -1; 2.判断cx中的值,不为0则转至标号处执行程序,如果为0,则向下执行。通常,用loop指令来实现循环功能,cx中存放循环次数。
48.在8086模式中,随意向一段内存空间写入代码是非常危险的,这段空间可能存放着重要的系统数据或代码,如果存放着系统数据或代码,就会报错,在一般的pc机中,DOS方式下,DOS和其他合法的程序一般都不会使用 0:200-0:300(00200h-00300h)的256个字节的空间。
第六章
49.程序取得所需空间的方法有两种:一是在加载程序的时候为程序分配,再就是程序在执行过程中向系统申请。
50.将数据、代码、栈放入不同的段:1.放到一个段中使程序显得混乱。2.对于8086模式,一个段的长度不能超过64k,如果数据、代码、栈加起来超过,就不能放在同一个段。
51.用和定义代码段一样的方法来定义多个段,然后在这些段里面定义需要的数据,或通过定义数据来取得栈空间。
52.一个段中的数据的段地址可由段名代表,偏移地址要看它所在的位置。
第七章 更灵活的定位内存地址的方法
53.and指令:逻辑与指令,按位进行与运算。通过该指令可将操作对象的相应位设置为0,其他位不变。例如指令 : mov al,01100011B and al,00111011B 执行后(al)= 00100011B。
54.or指令,逻辑或指令,按位进行或运算。通过该指令可将操作对象的相应位设置为1,其他位不变。
55.计算机中,所有信息都是二进制,而人能理解的信息是已经具有约定意义的字符。要把这些信息存储在计算机中,就要对信息进行编码。 编码方案:就是一套规则,约定了用什么样的信息来表示现实对象。
56.在汇编程序中,可以用“......”方式指明数据是以字符的形式给出的,编译器将把它们转为对应的ascii码。
57.除了用[bx]的方式来指明一个内存单元,还可以用一种更灵活的方式来指明内存单元:
[bx+idata]表示一个内存单元,它的偏移地址为(bx)+idata(bx中的数值+idata).
58.SI和DI是8086CPU中和bx功能相近的寄存器,SI和DI不能够被分成两个8位寄存器来使用。
59.前面使用[bx]和[bx+idata]的方式来指明一个内存单元,还可以用更灵活的方式[bx+si(di)]的方式来指明一个内存单元。它的偏移地址为(bx)+(si),即bx中的值加上si中的值。
也可以写成 mov ax,[bx][si]
60.还有一种方式: [bx+si+idata]或 [bx+di+idata],偏移地址为 (bx)+(si)+idata。
61.几种不同寻址方式比较:
(1)[idata] 用一个常量来表示地址。可用于直接定位一个内存单元。
(2)[bx] 用一个变量来表示内存地址,可用于间接定位一个内存单元。
(3)[bx + idata] 用一个变量和一个常量表示地址,可在一个起始地址的基础上用变量间接定位一个内存单元。
(4)[bx + si] 用两个变量表示地址。
(5)[bx + si + idata] 用两个变量和一个常量表示地址。
第八章数据处理的两个基本问题
62.基本问题:1.处理的数据在什么地方 2.要处理的数据有多长。
63.描述性符号表示 : reg表示一个寄存器 sreg 表示一个段寄存器。
64.Reg的集合包括: ax,bx,cx,dx,ah,al,bh,bl,ch,cl,dh,dl,sp,bp,si,di
65.sreg的集合包括: ds,ss,cs,es
66.在8086 CPU中,只有bx,si,di,bp这四个寄存器可以用在“[...]”中来进行内存单元寻址。
67.在[...]中,这4个寄存器可以单个出现,或只能以四种组合出现:bx和si,bx和di,bp和si,bp和di。
68.只要在[...]中使用寄存器bp,而指令中没有显性给出段地址,段地址就默认在ss中。
69.绝大部分机器指令都是进行数据处理的指令,处理大致可以分为三类:读取,写入,运算。在机器指令这一层来讲,并不关心数据的值是多少,而关心指令执行前一刻,它将要处理的数据所在的位置。指令执行前,所要处理的数据可以在三个地方:CPU内部,内存,端口。
70.汇编语言中数据位置的表达:
(1)立即数(idata):对于直接包含在机器指令中的数据(执行前在CPU的指令缓冲器中),在汇编中叫立即数,在汇编指令中直接给出。
(2)寄存器:指令要处理的数据在寄存器中,在汇编指令中给出相应的寄存器名。
(3)段地址(sa)和偏移地址(ea):指令要处理的数据在内存中,在汇编中用[x]的格式给出EA,SA在某个段寄存器中。存放段地址的寄存器可以是默认的。
71.指令要处理的数据有多长:8086Cpu的指令,可以处理两种尺寸的数据,byte和word。所以在机器指令中要指明操作的是字节还是字。
72.1.通过寄存器名指明要处理的数据的尺寸(通用寄存器有AX, BX, CX, DX等,这些都是字寄存器,其大小是16位
73.其中AX又由高8位的AH与低8位的AL组成,AH与AL都是字节寄存器,BX,CX,DX与AX类同)。 2.在没有寄存器名的情况下,用操作符 X ptr指明内存单元的长度,X在汇编指令中可以为byte或word。 3.其他方法:有些指令默认了访问的是字单元还是字节单元,比如push [1000h] 就不用指明访问的是字单元还是字节单元。
74.Div指令 :除法指令。1.除数:有8位和16位两种,在一个寄存器或内存单元中。2.被除数:默认放在AX或DX和AX中,如果除数为8位,被除数则为16位,默认在AX中存放;如果除数是16位,被除数则为32位,在DX和AX中存放,DX存放高16位,AX中存放低16位。 3.结果:如果除数为8位,则AL存储除法操作的商,AH存储除法操作的余数,如果除数为16位,则AX存储除法操作的商,DX存储除法操作的余数。
75.伪指令: db定义字节型数据 dw 定义字型数据 dd 定义双字型数据(每个占两个字的长度
76.dup是一个操作符,由编译器识别处理,配合db,dw,dd等数据定义伪指令,配合使用,用来进行数据的重复。 db 3 dup(0) === db 0,0,0。这个操作符十分有用,比如要定义200个字节的栈段: db 200 dup (0)
第九章 转移指令的原理
77.可以修改IP,或同时修改CS和IP的指令统称为转移指令。概括的讲,转移指令就是可以控制CPU执行内存中某处的代码的指令。
78.8086CPU的转移指令分为以下几类:1.无条件转移指令。 2.条件转移指令。 3.循环指令。4.过程 5.中断。
79.操作符offset:由编译器处理的符号,功能是取得标号的偏移地址。
80.jmp为无条件转移指令,可以只修改IP,也可以同时修改CS和IP。jmp指令要给出两种信息:1.转移的目的地址 2.转移的距离(段间转移,段内短转移,段欸近转移)。
81.CPU在执行jmp指令的时候并不需要转移的目的地址。但指令对应的机器码中包含的是转移的位移。这个位移是编译器根据汇编指令中的标号计算出来的。
82.实际上指令jmp short 标号 的功能是: (IP) = (IP) + 8 位位移。
(1)8位位移 = “标号”处的地址-jmp指令后的第一个字节的地址。
(2)Short指明此处的位移为8位位移。
(3)8位位移的范围为-128 -127,用补码表示。
(4)8位位移由编译程序在编译时算出。
还有一种相近的指令: jmp near ptr 标号 ,实现的是段内近转移。
83.转移的目的地址在指令中的jmp指令: jmp far ptr 标号 实现的是段间转移,又称为远转移。功能如下:
(CS) = 标号所在段的段地址; (IP) = 标号在段中的偏移地址。
Far ptr指明了指令yoga标号的段地址和偏移地址修改CS和IP。
84.转移地址在寄存器中的jmp指令: jmp 16位寄存器。功能 (IP) = (16位寄存器)
85.转移地址在内存中的jmp指令:
格式有两种:1.jmp word ptr 内存单元地址 (段内转移)
功能:从内存单元地址处开始存放着一个字,是转移的目的偏移地址。
2.jmp dword ptr 内存单元地址 (段间转移) 功能:从内存单元地址处开始存放着两个字,高地址处的字是转移的目的段地址,低地址处是转移的目的偏移地址。
86.jcxz指令为有条件转移指令,所有的有条件转移指令都是短转移,在对应的机器码中 包含转移的位移,而不是目的地址。对IP的修改范围都为 -128 - 127。
87.Loop指令是循环指令,所有循环指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址。对IP的修改范围都为:-128 - 127。
88.根据位移进行转移的目的: jmp near ptr 标号, jmp short 标号,jcxz 标号,loop 标号等几种汇编指令,他们对IP的修改是根据转移目的地址和转移起始地址之间的位移来进行的。在他们对应的机器码中不包含转移的目的地址,而包含的是目的地址的位移。这种设计,方便了程序段在内存中的浮动装配。
89.根据位移进行转移的指令,他们的转移范围受到转移位移的限制,如果在源程序中出现了转移范围超界的问题,在编译的时候,编译器将报错。
第十章 Call和ret指令
- ret指令用栈中的数据修改IP的内容,从而实现近转移。
91.retf指令用栈中的数据修改CS和IP的内容,从而实现远转移。
92.CPU执行call指令的时候,进行两步操作:
(1)将当前的IP或CS和IP压入栈中。
(2)转移。
Call指令不能实现短转移,除此之外,call指令实现转移的方法和jmp指令的原理相同。
93.mul指令是乘法指令:
(1)两个相乘的数:要么都是8位,要么都是16位,如果是8位 一个默认放在AH中,另一个放在8位寄存器或内存字节单元中。如果是16位,一个默认在AX中,另一个放在16位寄存器或内存单元中。
(2)结果:如果是8位乘法,结果默认放在AX中,如果是16位乘法,结果高位默认在DX中存放,低位在AX中存放。
94.我们不可能简单的用寄存器来存放多个需要传递的数据,对于返回值,也有同样的问题,这时候我们将批量数据放到内存中,然后将它们所在内存地址空间的首地址放在寄存器中,传递给需要的子程序。
第十一章标志寄存器
95.CPU内部的寄存器中有一种特殊寄存器(对于不同的处理机,个数和结构都可能不同)具有三种作用:
(1)用来存储相关指令的某些执行结果。
(2)用来为CPU执行相关指令提供行为依据。
(3)用来控制CPU的相关工作方式。
这种特殊的寄存器在8086CPU中,被称为标志寄存器flag,它的每一位都有特定的含义。
8086中flag的 1 ,3 ,5 ,12 ,13 ,14 ,15位没有使用,不具有任何含义。其他的都有特定含义。
96.Flag中的第6位是ZF,零标志位。它记录相关指令执行后,其结果是否为0.如果结果为0,那么ZF = 1,如果不为0,ZF = 0;第二位是PF,奇偶位标志。记录相关记录执行后,其结果的所有二进制位中1的个数是否为偶数。如果1的个数为偶数,PF = 1,反之 PF = 0.
97.Flag的第七位是SF,符号标志位。记录相关指令执行后,结果是否为负数。如果为负,SF = 1,反之SF = 0。
98.Flag第0位是进位标志位CF。一般情况下,在进行无符号数运算的时候,它记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值。
99.Flag的OF标志:如果运算结果超出了机器所能表达的范围,将产生溢出。第11位是溢出标志位,如果发生了溢出,OF = 1,反之 OF = 0;
100.adc指令:是带进位加法指令,它利用了CF位上记录的进位值。
101.Sbb 是带借位减法指令,它利用了CF位上记录的借位值。
102.Cmp比较指令,相当于减法,只是不保存结果。cmp指令执行后,将对标志寄存器产生影响。
103.Flag的第10位是DF,方向标志位。在串处理指令中,控制每次操作后si,di的递减。
(1)DF = 0 每次操作后si,di递增。
(2)DF = 1 每次操作后si,di递减。
8086CPU提供下面两条指令对DF位进行设置:
cld指令:将标志寄存器的DF位置0
std指令:将标志寄存器的DF位置1
104.pushf的功能是将标示寄存器的值压栈,而popf是从栈中弹出数据,送入标志寄存器中。这两种为直接访问标志寄存器提供了一种方法。
第十二章 内中断
105.对于8086CPU,当CPU内部有下面的情况发生的时候,讲产生相应的中断信息:除法错误 ,单步执行 执行int0指令 执行int指令。
106.8086CPU用称为中断类型码的数据来标识中断信息的来源。中断类型码为一个字节型数,可以表示256种中断信息源。上面对应的是 : 除法错误 (0) 单步执行(1)执行int0指令(4)
第十三章int指令
107.Int 指令的格式 : int n ,n为中断类型码,它的功能是引发中断过程。
108.在系统板的ROM中存放着一套程序,称为BIOS(基本输入输出系统),主要包含以下内容:1.硬件系统的检测和初始化程序。 2. 外部中段和内部中断的中断例程。 3.用于对硬件设备进行I/O操作的中断例程。 4.其他和硬件系统相关的中断例程。
第十四章端口
109.CPU可以直接读写3个地方的数据:1.CPU内部的寄存器 2.内存单元 3.端口
110.访问端口的时候,CPU通过端口地址来定位端口,因为端口所在的芯片和CPU通过总线相连,所以,端口地址和内存地址一样,通过地址总线来传送。在PC系统中,CPU最多可以定位64K个不同的端口。则端口的地址范围0-65535。
111.对端口的读写不能用 mov,push ,pop等指令。端口的读写指令只有两条: in和 out。分别用于从端口读取数据和往端口写入数据。
112.shl 是逻辑左移指令,功能:1.将一个寄存器或内存单元中的数据向左移位。2.将最后移出的一位写入CF中 3. 最低位用0补充。
113.shr是逻辑右移指令,它和shl相反,1.将一个寄存器或内存单元中的数据向右移位。 2.将最后移出的一位写入CF中。 3.最高位用0补充。
第十五章外中断
114.在PC系统的借口卡和主板上,装有各种接口芯片。这些外设接口芯片的内部有若干寄存器,CPU将这些寄存器当做端口来访问。外设的输入不直接送入内存和CPU,而是送入相关的接口芯片的端口中;CPU向外设的输出也不是直接送入外设,而是先送入端口中,再由相关的芯片送到外设。
115.在PC系统中,外中断源一共有两类:1.可屏蔽中断:可屏蔽中断是CPU可以不响应的外中断。是否响应,要看标志寄存器IF位的设置。如果IF = 1,则CPU在执行完当前命令后响应中断。如果IF = 0,则不响应。 2. 不可屏蔽中断:CPU必须响应的外中断。对于8086CPU,不可屏蔽的中断的中断类型码固定为2,所以中断过程中不需要取中断类型码。