版权声明:本文为博主原创文章欢迎分享到其它技术社区,分享请标明出处: /CHENYUFENG1991/article/details/
经典汇编程序100例语言应该是我们现在学的最“低级”的语言了因为现在不会再有人去学機器语言了。而经典汇编程序100例语言还在一些硬件或者嵌入式设备上使用并开发着以下资料是为了大学的经典汇编程序100例考试整理的资料,现在与大家分享希望能给大家提供帮助。
计算机主要由运算器、控制器、存储器和输入输出设备五大部件构成
一个存储单元中存放的信息称为该存储单え的内容
在1M的存储器里每一个存储单元都有一个唯一的20位地址,称为该存储单元的物理地址
如:假设TABLE是在数据段定义的一个字节数组的首地址标号,偏移地址为1000H
基址变址寻址方式:操作数的偏移地址是两个指定寄存器的值之和
可以用段超越湔缀重新指定段寄存器:
四类传送指令:通鼡传送指令、累加器专用传送指令、地址传送指令、标志传送指令
LDS:指针送指定寄存器和DS寄存器
LES:指针送指定寄存器和ES寄存器指令
ADD和ADC指令两个操作数不能同时为存储器寻址方式,并且目的操作数不能为立即数寻址方式
CF表示机器的最高有效位向更高有效位的进位。
位移量不同转移范围不同。当位移量位8位只允许转移到与本条指令的下一条指令相距-128~127范围内的存储单元中。当位移量位16位时允许转移到当前代码段内任何地方。
137.位移量可以是一个带符号的8位数也可以是一个带符号的16位数。表示了转移地址偏移本条指令的下一条指令的字节数负数表明要向当前指令的后面跳转,整数要向当前指令的前面跳转
142.两个无符号数比较大小时机器根据CF标志位来判断大小,即两无符号数相减若不够减,則最高位有借位CF=1;否则CF=0。
144.比较两个数相等则转移,否则顺序执行
(2)格式:JMP 存储器寻址方式
(2)格式:JMP 段地址值:偏移地址
155.所有JMP指令都不影响状态标志位
(3)段内带立即数返回
(4)段间带立即数返回
操作:判断测试条件,若条件成立则IP?(IP)+8;若条件不成立,则IP保持不变
159.从寄存器里取数据比从存储器里取数据快得多从而提高了指令执行速度。
162.注意寄存器间接寻址和相对寻址的区别
163.寄存器相对寻址:操作数的偏移地址是指定寄存器的值与一个整数之和
167.相对基址变址寻址
168.两个段寄存器之间不允许直接传送數据
注意:入栈时,SP-2
175.完成两个字节数据相加
176.伪指令语句也叫指示性语句只是用来指示、引导经典汇编程序100例程序在经典汇编程序100例过程中做一些操作,为经典汇编程序100例程序在翻译时提供有关信息并不翻译机器代码的语句。
187.一条语句可以写在多行上续行符是&
189.EQU伪操作中的表达式是不允许重复定义的,而=伪操作允许重复定义
191.操作数“?”可以保留存储空间但不存入数据。待到程序运行时存放中间戓最终结果
193.实现两个32位数的乘法程序
194.将一个字节压缩BCD码转化成两个ASCII码
195.利用直接查表法完成将键盘输入的一位十进制数(0~9)转换成对应的平方值并存放在SQRBUF中。
196.从键盘输入一个小写字母将其转化成大写字母在屏幕上显示絀来。
197.在内存中有一个字节单元NUM存有带符号数据,要求计算绝对值放入RESULT单元中。
198.多分支结构实现方法:条件选择法跳跃表法,地址表法
200.SHL:将操作数逻辑左移指定次数
201.除法指令要求被除数的长度必须是除数的两倍
在除法中,被除数也即目的操作数隐含在AX(字节运算)或DX-AX(字运算)中除数即源操作数。
AX可以分别访问高位字节AH和低位字节AL
207.使用ASSUME伪操作来明确段和段寄存器的关系
211.操作码:指明要完成操作的性质
225.IP是指向下一次要取出嘚指令与CS寄存器配合才能形成真正的物理地址。
237.1个字节8位1个字16位,1个双字32位
241.物理地址计算:
244.每个存储单元在存储器中所具有的地址称为存储单元的物理地址段基地址是每一段的起始地址,单元与段基地址的距离称为段内偏移地址也叫偏移量。
250.默认情况下认为操作数有效地址的作用域是DS所指向的数据段,但允许使用段超越前缀指定为其他段即对于寻找操作数来说,还允许操作数在以代码段、堆栈段或附加段为基准的区域中只要在指令中指明是段超越的。16位地址偏移量可以与CSSS,ES相加作为操作數的地址。如MOV AX,ES:[2000H]
251.寄存器间接寻址可以是16位或32位的
254.若是以寄存器BP间接寻址则操作数在堆栈段中,SS左移4位后与BP相加作为操作数的地址
“ES”和“DS”分别是两指令的段超越前缀。
258.若在指令中规定是段超越的则BP也可以与其他的段寄存器相加,形成操作数地址如:
274.经典汇编程序100例语言对指令的大小写是不敏感的
276.OFFSET AREA1 是指地址单元AREA1在段内的地址偏移量。寻找内存操作数时必须以段地址(在某个段寄存器中)加上此单元的段内地址偏移量,才能确定某一内存单元的物理地址
281.LEA指令可以用相应的源操作数为立即数的MOV指令代替。
285.通过查表转换指令求0~9中任意一个数的平方
执行后:(AL)=25
286.实现存储器操作数與立即数相加/减,与累加器或别的寄存器相加/减和/差放到该存储单元中。
287.指令SBB [DI],100 实现的功能是用DS:[DI]所指单元的内容减去100再减去CF结果送到DS:[DI]指向的字节单元中。
说明:JG为判断带符号数的大小若大,则转移到后面的标号
MUL:实现两个无符号数相乘,ALAX或EAX的内容和OPRD的内容是两个无苻号数,且如果OPRD长度为8位则与AL内容相乘,相乘结果送到AX中;
299.某个操作数自己和自己相“与”,操作数不变可以使CF=0.
301.在实地址方式下,段寄存器的内容左移4位而得到段基地址
304.根据程序的实际情况,SS,DS,ES也可以没有只有CS是必不可少的。每个程序至少必须有一个
310.操作数是字符串时,内存中存放的是每个字符的ASCII码
311.复制操作苻DUP表示操作数重复若干次。
319.三个数相加把结果放在SUM单元中。
323.宏调用展开在编译处在EXE攵件中有N份。
326.在经典汇编程序100例中字符就和字符串一样是同一个概念,都用单引号字符就是长度为1的字符串。
334.$表示当前地址
335.经典汇编程序100例上机过程:
336.经典汇编程序100例程序的主要功能:
$用在伪操作的参数字段时,表示的是地址计数器的当前值
347.ORG伪操作:用來设置当前地址计数器的值。
如常数表达式的值为N则ORG伪操作可以使下一个字节的地址成为常数表达式的值N。
353下列传送指令中有语法错误嘚是(A)
354.逻辑移位指令SHR用于:D
J寄存器AX的值是(C)
358.简述经典汇编程序100例语言的上机过程:
259.执行段内返回RET指令时,执行的操作是:
260.执行段间返回RET指令时执行的操作是:
261.当中断发生时,由中断机构自动完成哪些动作(中断过程)
265.串重复前缀指令
266.在串操作指令前使用重复前缀指令REPE终止串的重複操作条件是(C)
267.下面指令中,合理而有意义的指令是(D)
MOVS是串传送指令MOVSB传送一个字节
268.下面的数据传送指令中,错误的操作是(D)
立即數不能直接送段寄存器即段寄存器只能通过寄存器或存储单元传送数据。
269.执行下列指令后正确的结果是(B)
271.测试BL寄存器内容是否与4FH相等,若相等则转NEXT处执行代码为(B)
273.PSW寄存器共有6位条件状态位,3位控制状态位
276.注意NEG是求补,而不是求反
RCR:带进位循环右移指令
RCL:带进位循环左移指令
该程序段已占有的存储字节数是多少?
注意:EQU定义的符号洺不占存储空间
ORG是设置该程序段的偏移地址。
282.循环控制指令测试条件
283.循环控制指令LOOPNZ/LOOPNE控制循环继续执行的条件是(B)
284.压缩BCD码指每个字节存储两个BCD码
285.使计算机执行某种操作的命令是(B)
286.將数据5618H存放在存储单元中的伪指令是(B)
288.如TABLE为数据段中0100单元的符号名其中存放的内容为0FF00H,以下两条指令有什么区别AX寄存器的内容分别是什么?
289.对于下面的数据定义三条MOV指令分别经典汇编程序100例成什么?
291.无符号数比较时用“高于”或“低于”来做判断依据。
转移指令中大部分指令可以用两种不同的助记符来表示。比如一个数低于另一个数囷一个数不高于也不等于另一个数是等同的。
292.比较两个无符号数的大小
294.变量TABLE中存放了一个偏移地址当无符号数X小于、等于或大于此偏移地址时,应去执行三个鈈同的程序段
295.比较两个有符号数
有符号数仳较条件转移指令
296.试分析下面程序段的功能是什么
判断AL的内容,若为‘A’~‘Z’的大写字母时程序段 LETTER处理,否则转OTHER处理
297.计算机中为便於存储及计算机的物理实现,采用(A)
299.机器指令是在程序运行期间由计算机来执行的。
300.伪指令在程序(B)阶段被处理。
301.在程序的开始可以用NAME或TITLE作为模块的名字但NAME和TITLE偽指令不是必要的。
302.一个完整、独立的经典汇编程序100例语言源程序可以没有(C)伪指令
306.从微处理器的角度来看,计算机结构可分为CPU、内存、和IO子系统三个主要部分
320.操作系统1号功能调用(输入一个字符)
321.已知在内存中有一个字节单元NUM,存有带符号数据要求计算它的绝对徝后,放入RESULT单元中
322.编写计算下面函数值的程序:
323.程序:把BX寄存器内的二进制数用十六进制数的形式在屏幕上显示。
324.程序:在ADDR单元中存放著数Y的地址编一程序把Y中1的个数存入COUNT单元中。
327.偏移量=偏移地址=有效地址=段内地址
329.過程定义伪指令
336.H计算机刚一启动时物理地址是多少?
339.实模式就是一般模式僦是我们常用的模式。
341.8086微处理器由哪几部分组成
功能:完成IO端口对累加器的数据输入
操作:(IO地址表达式)?AL
功能:完成累加器对IO端口的数据输出
348.输入字符代码:
349.试编制一程序:从键盘输入一行字符,要求第一个键入的字符必须是空格符洳不是,则退出程序;如是则开始接收键入的字符并顺序存放在首地址为BUFFER的缓冲区中(空格符不存放),直到接收到第二个空格符时退絀程序
351.调用程序和子程序在同一代码段中
352.调用程序和子程序不在同一个代码段中
354.子程序作主程序
366.在微处理器中,PUSH和POP指令在堆栈与寄存器或存储单元の间传送数据时一次总是传送2个字节。
370.子程序作主程序必须用FAR
372.期中考试2个编程。
376.下列指令中哪条是正确的(D)
A错:立即数不能直接送段寄存器,即段寄存器只能通过寄存器或存储单元传送
377.使8086/88的标志寄存器F中的中断标志I置为关中断的命令是CLI。
注意:堆栈中数据的压入弹出必须以字节为单位所以PUSH和POP指令呮能作字操作。
383.中断系统的中断矢量表用来存放中断类型号共预留了1KB个字节空间。
387.已知AL=3分析下列程序段:
388.画图说明下列语句所分配的存储空间及初始化的数据值。
391.操作数可以保留存储空间,但不存入数据得到程序运行时存放中间或最终结果。
394.根据伪指令代码写内存凊况是难点和必考点应该再次复习。尤其搞懂关于字符串的存放问题DB和DW是不一样的,应再次学习
395.BP、SP可称为指针寄存器
396.一般在作双字长运算时把DX和AX组合在一起存放一个双字长数,DX用来存放高位字
398.段寄存器也是一种专用寄存器,专用于存储器寻址鼡来直接或间接的存放地址。段寄存器的长度为16位
399.在存储器里以字节为单位存储信息。
408.段寄存器和偏移地址的默认组合
409.寻址方式分为:数据寻址和指令寻址
419.有符号数比较大小:机器根据SF标志位来判断大小即若被减数小于减数,差值为负则SF=1;否则SF=0;前提是无溢出 OF=0.
421.名字的定义规则:
422.经典汇编程序100例字符串用单引号,如:‘ABC’
第一个AND是逻辑运算指令,第二个AND是逻辑运算符
425.在经典汇编程序100例阶段处理:伪指令、宏指令、运算符
428.某系列微机对存储器分段,如果每一个段最多嘚字存储单元(16位二进制)是32K那么表示段内字节单元偏移地址的二进制位数应是(B)
431.MOV指令中目的操作数不能为立即数和CS。
434.执行下列指令后AX寄存器中的内容是什么?
435.指令的操作数中允许出现表达式,例如BUF1与BUF2均为变量名下面指令中语法正确的是(D)
436.在的立即数寻址方式中,对寄存器的使用下列说法正确的是(D)
437.在DEBUG中为查看或修改内存单元的内容,使用的命令是(A)
E命令:将内容写入内存
438.对CS段寄存器赋段地址的方法是(B)
(2)段间带立即数返回
440.8086CPU中,一个段最大可定义的字节数是(C)
441.软中断指囹INT 21H执行若AH=9时则完成的功能是显示字符串。
444.编写指令将附加段中的一个芓节变量COUNT送给AL寄存器
446.最后移位指令吐血总结:
RCL:带进位的循环左移,每一位先加上CF的值然后循环左移到最低位,原来的CF移到最低位;
1 本讲座以经典汇编程序100例初学者戓对经典汇编程序100例一点也不了解的读者为对象经典汇编程序100例高手不属于该范围,但强烈建议高手指导并增补、修改本文
2 任何读者鈳以跟此贴,提出疑问或解答其中的问题,但对于所有跟贴水贴、内容有错、毫不相干贴将直接删除,有意义的贴可能会合并到下一講的内容中合并后也将删除,请跟贴者谅解同时按学习进步,请提问者逐步提不要我没开口,你就问怎么编个病毒的问题
3 借以抛磚引玉,但不希望大家只朝我扔砖头希望大家踊跃思考,使之完善
大家坐好了,不要,不要不要,男女同学不要相互女同学不偠对我….
1 经典汇编程序100例需要什么工具和程序,到哪里下载
目前阶段,经典汇编程序100例程序仅需要两个程序就够了: masm.exe,link.exe前者是编译程序,后者是链接程序
另外,为了验证和调试程序还需要一个程序debug.exe,该程序由windows本身就提供所以就不提供下载地址了。
将二者下载后放箌某一个目录中(任意目录都可以),考虑到很多命令需要通过键盘敲入所以建议你不要把文件放入到长文件名目录、中文目录或很深嘚目录中。比如你可以建一个“D:\Masm”目录并建议此后的程序都放这个目录,此后称这个目录为经典汇编程序100例目录
2 学习经典汇编程序100例需要有哪些编程方面的知识。
没有任何编程方面的知识学习此语言等于缘木求鱼,所以请放弃学习的想法一般来说至少要知道如下几點:
*)程序的运行逻辑结构有顺序(按语句依次执行)、分支结构(IF…THEN…ELSE…),循环结构(FOR…NEXT)三种结构
*)知道什么是子程序,什么是调用
*)经典汇编程序100例程序员的视角。不同编程视角编程要求是不一样的比如删除文件,
>>用户的视角是找到“删除”按钮或菜单然后单擊一下即可。
>>高级程序员的视角是知道删除的文件并发出删除命令。这些通过API实现
>>经典汇编程序100例程员的视角是得到要删除的文件名,找到该文件所在位置通过调用删除“中断命令”进行删除。
>>操作系统开发人员的视角则是接到删除命令后先找到系统根目录区,由根目录区的链接依次找到子目录区直到找到要删除的文件,然后按照操作系统删除文件的规则对该文件名进行修改比如DOS,只把第一个芓符改成"?"
按程序语句等价的角度看,一行VB的打印语句用经典汇编程序100例实现大约需要一百二十多行。知道经典汇编程序100例语言的视角後就要知道前面的道路是坎坷的,没有耐心是不行的想通过几分钟几行程序就完成很复杂的操作不是件容易的事。
经典汇编程序100例产苼于DOS时代或更早而现在是Windows时代,所以可能遗憾地说:尽管还有批牛人在用经典汇编程序100例开发核心级程序但我们几乎没什么用,除了必要时间能拿来分析一两个程序的部分代码之外别的也就没干什么用了。并且并不是所有的经典汇编程序100例命令都能在windows下使用而泛泛哋追求“时髦”而学本语言,最后的结果是损了夫人又折兵所以学之前你要考虑好。我劝那些为了当“黑客”而学经典汇编程序100例的人僦此止步
1 一个经典汇编程序100例程序的编译过程是怎么样的。
1)首先你需要找一个编辑器编辑器用任何“纯文本”编辑器都可以。比如記事本编好以后保存到经典汇编程序100例目录中。扩展名为asm比如myfirst.asm。但这里建议你找一个能显示出当前行的编译器这样出错后排错很容噫。
2)然后在DOS下进入D:\Masm目录中输入“masm myfirst.asm",如果有错系统会提示出错的行位置和出错原因
2 宏经典汇编程序100例和经典汇编程序100例有什么区别吗?
二者的区别在于前者提供宏后者不提供。后者已找不到了所以你可以认为二者没有区别。
3 机器语言、经典汇编程序100例语言、高级语訁的关系
最早的计算机采用机器语言这种语言直接用二进制数表示,通过直接输入二进制数插拔电路板等实现,这种“编程”很容易絀错每个命令都是通过查命令表实现,既然是通过“查表”实现的那当然也可以让计算机来代替人查表实现了。于是就产生了经典汇編程序100例语言所以不管别人怎么定义机、汇语言,我就认为二者是等价。后来人们发现用经典汇编程序100例语言编某一功能的时候,連续一段代码都是相同或相似于是就考虑用一句语言来代替这一段经典汇编程序100例语言,于是就产生了高级语言因此,所有高级语言嘟能转化成经典汇编程序100例语言而所以经典汇编程序100例语言又可转化成机器语言。反之所有机器语言可以转成经典汇编程序100例语言(洇为二者等价)。但并不是所以经典汇编程序100例语言都能转成高级语言
通常都把计算机定义成五部分:运算器、控制器、存储器、输入系统、输出系统。
为了简单其间我们如此理解:运算器+控制器=CPU。存储器=内存(暂不包括外存永不包括CACHE)。输入系统=键盘(不包括鼠标)输入系统=显示器(不包括打印机,绘图仪)
5 寄存器和内存的区别
寄存器在CPU中。内存在内存条中前者的速度比后者快100倍左右。后面嘚程序要求每条指定要么没有内存数据要么在有一个寄存器的参与下有一个内存数据。(也就是说不存在只访问内存的指令)。
与生活中的计数不一样经典汇编程序100例中的计数是从0开始的。比如16个计数则是从0~15,而不是生活中的1~16这一点看起来简单,真运算起来就不昰件容易的事了不信等着瞧。
又与生活中不一样的地方是进制切记下面的常识:
*)计算机内部存储都用二进制。
*)我们的经典汇编程序100例源程序默认都用十进制(除非你指明类型)
*)我们用的调试程序debug默认的都是十六进制。(无法指明其他类型)
其中十六进制的十六個个位数依次是:01,23,45,67,89,AB,CD,EF。
好了结合6,78三条。大家来算一个“题”某一组数据显示时,每个数据占了四個位置
每行共十六个。问:十六进制的13位置在哪里(第几行第几列)。
程序在内存中访问内存是几乎每一程序都要进行的操作,计算机对内存编址是线性的也就是说是一维的,比如256M的内存地址就应该是从0~(256M-1),这个地址称为物理地址或绝对地址
但从经典汇编程序100例程序员的角度看,内存却是二维的要说明一个地址,需要给出两个值就象你在平面上指定一点需要说出(X,Y)坐标一样经典汇编程序100例程序员的内存视角也需要两个“坐标”,前一个称为段地址(Segment)后一个称为偏移地址(Offset),该地址称为逻辑地址
比如“”就是一個地址。“1F3F:”不是一个地址因为他只有段地址,没有编移地址注意此后的地址都用十六进制表示。
前面提到计算机编址是一维的,经典汇编程序100例程序员是二维的那么二者怎么换算呢?由后者到前者的换算方法是“段地址串”后面加个“0”,然后再加上偏移地址
比如“”(十六进制的加减运算参见相关资料)
16135 ’注意此串仍然是十六进制。
所以经典汇编程序100例程序员眼中的地址“1234:3DF5”就是物悝地址(计算机编址):16135。
知道了由后者向前者的转换那么由前者向后者的转换呢?
“不知道”为什么不知道,继续往下看
1.3 到底哪個地址对。
知道了1.2的地址算法后我又发现一个问题:
那么到底哪个对呢?问题的回答是这样的:假设我现在让你按一下“L”键我可以告诉你如下几种方法中的一种或几种。1 请按一下“L”键; 2请按一下键盘上第四行第十个键;3 请按一下第十列中的第四个键;4 请按一下“K”祐边的键;5 按标准指法单击一下右手无名指
举上面的例子也就是说,同一个地址有很多种表示方式具体用哪一种,要看实际使用时的凊况但无论用哪种方式,只要能达到目的即可(实际中该问题一般不会受此问题困扰,但初学时突然想不通)
1.4 有多少内存可以访问
無论是段地址还是偏移地址都是四位十六进制(如果不够四位,前面补0)也就是说:总共可以访问的地址说是:0000:0000~FFFF:FFFF。 总共FFFF0+FFFF+1=10FFF0个地址也僦是不到1M的空间。
*)不管你实际内存有多少目前我们只能访问不到1M的空间。
*)而实际上连这1M也用不完其中上端的384K的址只能读不能写,呮能读一般称为ROM。
*)低端的640K可以读写但这640K的低端100多K也不能随便写,因此DOS系统使用该区
*)原来1024M的内存,经典汇编程序100例程序只能使用其中400多K这段内存的容易相当于一个普通文档的大小。不过这就足够了
先记住以下两个命令:D命令和Q命令。前者是显示内存内容后者昰退出DEBUG命令。
————-以下为抄别的人内容—————
DEBUG.EXE程序是专门为分析、研制和开发经典汇编程序100例语言程序而设计的一种调试工具具有跟踪程序执行、观察中间运行结果、显示和修改寄存器或存储单元内容等多种功能。它能使程序设计人员或用户触及到机器内部因此可以说它是80X86CPU的心灵窗口,也是我们学习经典汇编程序100例语言必须掌握的调试工具
在DOS提示符下键入命令:
这时屏幕上出现DEBUG的提示符“-”,表示系统在DEBUG管理之下此时可以用DEBUG进行程序调试。若所有选项省略仅把DEBUG装入内存,可对当前内存中的内容进行调试或者再用N和L命令,从指定盘上装入要调试的程序;若命令行中有文件名则DOS把DEBUG程序调入内存后,再由DEBUG将指定的文件名装入内存
功能:退出DEBUG,返回到操作系统
(2)显示存储单元命令 D
格式1:D[起始地址]
格式2:D[起始地址][结束地址|字节数]
功能:格式1从起始地址开始按十六进制显示80H个单元的内容,烸行16个单元共8行,每行右边显示16个单元的ASCII码不可显示的ASCII码则显示“·”。格式2显示指定范围内存储单元的内容,其他显示方式与格式1┅样。如果缺省起始地址或地址范围则从当前的地址开始按格式1显示。
说明:在DEBUG中地址表示方式有如下形式:
段寄存器名:相对地址,如:DS:100
段基值:偏移地址(相对地址)如:23A0:1500
————————–小抄结束——————————–
格式1:E[起始地址] [内容表]
功能:格式1按內容表的内容修改从起始地址开始的多个存储单元内容,即用内容表指定的内容来代替存储单元当前内容
表示从DS:0100 为起始单元的连续五个芓节单元内容依次被修改为
格式2是逐个修改指定地址单元的当前内容。
其中156F:0010单元原来的值是41H5FH为输入的修改值。若只修改一个单元的内容这时按回车键即可;若还想继续修改下一个单元内容,此时应按空格键就显示下一个单元的内容,需修改就键入新的内容不修改再按空格跳过,如此重复直到修改完毕按回车键返回DEBUG“-”提示符。如果在修改过程中将空格键换成按“-”键,则表示可以修改前一个单え的内容
——————-小抄结束—————-
5 使用DOS时,经典汇编程序100例用户可以从DOS操作系统中得到什么
现在编程,通常很多功能都是通過调用系统API很多高级语言都直接把这些API包装起来,以系统接口或函数的方式提供给用户那么经典汇编程序100例函数都能得到什么呢?
首先经典汇编程序100例用户有很多东西可以调用。他们主要是:
5.1 BIOS提供的接口现在硬件与软件的区分已越来越不明显,很多硬件不仅仅是电蕗而还要提供一些固化写入硬件的一部分“程序”,这些程序以ROM的方式出现经典汇编程序100例用户最大的好处就是可以直接使用这些“程序”,这些使用不仅功能强大而且效率非常高。
5.2 DOS功能调用作为操作系统也象BIOS一样向用户提供了相应的“程序”。这些程序在很大程序上扩充了BIOS与BIOS不同的是,这部分程序放在内存中它可以被修改。而BIOS中不能再修改
以上两种接口都通过一种相同的格式调用,这些程序统称为“中断”现在先不要理解中断的本意,你现在可以认为是系统提供给你的函数
5.3 系统共享数据区。编过程序的人都知道全局变量的好处全局变量方便之外在于任何函数、过程都可以调用、读取、修改。全局变量不足之处是危险性有一个过程改了这个变量值,其它的也得跟着改变了DOS操作系统同样也提供了这样的共享数据区,该区是整个系统的共享区任何程序都可以查找、修改。当然修改某处必然会对其它程序造成影响。
前面5.2已提到中断了,现在问题是不同硬件不一样即使相同硬件的ROM,不同版本各个BIOS中断程序所处的位置吔不一样,DOS中断也一样不同版本、不同配置,在内存位置也不一样那么你使用某一个中断,系统怎么知道你使用的那个中断程序在哪呢
为了解决这一问题,DOS会在启动的时候把所有这些(BIOS和DOS)中断的首地址保存到一个地址。这个地址很容易记这段地址是内存的绝对零地址()。前面已讲过每个地址在经典汇编程序100例程序员角度来看是二维的,也就是分为段地址和偏移地址每个地址各占两个字节,所以要表示这个二维地址需要4个字节所以每个中断首地址由4个字节表示。一共256个中断占用了1024个字节的位置。
另外需要注意的是这4個表示地址的字节,数据是由低向高的比如12 34 56 78所表示的地址是:。
一般用INT M表示中断M如果M是十六进制,则在后面加上一个H比如19号中断,┿六进制应该是13H所以该中断就是INT 13H。
7 再谈系统共享数据区
该共享数据区在绝对地址:开始
之所以把这个内存单独放一章,是为了说明它嘚重要性后面的几乎很多程序都需要你对这一章的理解。这里的内存映象就是指当你把一个可执行文件(EXE或COM文件)放到内存后整个内存“看”起来是什么样子的。
前面讲过这里经典汇编程序100例程序只能访问1M的内存空间,所以下面就以1M内存为例并且以DOS操作系统作为讲解对象,所以所编出来的程序也仅是DOS程序事实上,通过winasm可以访问远远超过1M的空间并且可以编出FOR windows的程序。但那是另外的话题我们暂且鈈说那些。
首先这1M内存如果我们不再以二维的方式看,而是一维的线性地看(二维和一维的转化方式参见前面章节)。但描述还是以②维的方式描述从最底端到最高端依次是:
1 中断向量区:该区由00:03FF。这里存着系统的所有中断的中断向量表对于中断向量表,你现在先悝解为一些程序的首地址由这个地址你就能找到该程序。
2 系统数据区:该区由40:XXXX(不好意思忘了),这里存着整个系统中DOS操作系统要鼡的数据,由于这个区的数据对用户是开放的所以用户当然也可以从这里读出来用。
3 DOS操作系统区:操作系统常驻内存你向计算机发的烸个命令其实都是操作系统执行的。这个区的大小主要是由操作系统的版本和用户的配置大小决定如果是驱动程序配置,就放到根目录丅的config.sys里如果是程序,就放到autoexec.bat里这里设置在现在的windows 95/98/nt/me/2000/xp/2003中仍然有,所以我就不多说了
用户程序,这个当然就是你执行的程序了这种程序汾两种,一种是扩展名为com文件一种是exe文件,从程序内睝@矗?罢叱绦虻乃母龆沃睾希ê竺嬉?舱馑母龆危???宰畲蟪ざ戎坏扔谝桓龆危?們懊娑蔚刂返睦斫饩褪莄om文件最大只能是64K所以com文件只适合小的程序。而exe四个段可任何分配,并可扩充段而且每个段的段地址可以任哬改动,因此exe的访问内存能力大多了这种格式访问能力只受地址结构的限制了。
用户程序所占的内存大小完全由程序本身决定但最大,只能到640K这一点,怪不得别人只能怪当前计算机软硬件设置高手高手高高手们(包括比尔盖茨)们的失误了,60年代的超级计算机只有36K嘚内存所以他们就在80年代得到一个结论:640K的内存足够了。
如果用户程序大于由操作系统所占内存的顶底到640K之间的内存量就会显示:内存不够,因而程序不能执行这种现象对于一开始就用windows的人来说,几乎没见过但对于一开始用DOS并打汉字的人来说,再正常不过如果小於这段内存,多余部分就空着
5 从640K到1M-64K,这段内存就很难说清了这段内存中有一部分被硬件占有,有一部分是显示缓冲区点有还有一部汾是系统ROM占有。
6 从1M-64K到1M之间的这段64K的内存叫作HMA这段内存是小孩没娘,说来话长我们先不说他。
2.2 验证上面的理论
中断向量表就是所有中断姠量首地址表这里保存着每个中断程序的首地址,几乎所有的经典汇编程序100例书都把中断后面后面的章节中并且对中断的解释也仅从芓面意思解释,所以导致大学对中断的不重要和误解没耐心的没到这个章节就不学经典汇编程序100例了,有耐心的到这里才豁然开朗我現在不讲中断的原意。我直接告诉你你把中断当成API也许更合适。也就是说别人把很多已作好的功能放到了内存中。并且把调用这一功能的号告诉了你你只要调用这些功能号,系统就自动从这个中断向量表中找到对应的中断然后执行你的功能。
首先让你感受一下中断嘚魅力一下吧比如中断21H的2A功能调用是读取系统的日期,这个调用的规则是调用前AH寄存器置为2A。调用后年在CX中月在DH中,DL在日中星期茬AL中。
从中断的作来与中断向量表又有什么关系呢原来你在经典汇编程序100例里运行int 21时,系统就在上面的中断向量表中找到int 21的中断地址該中断的地址应该位于:00:0087,具体算法前面已说明了
找到内容是:00A7:107C。然后系统就转到这个地址执行int 21
2.2.2 系统数据区前面都已说明过。不再多說系统区,很多DOS中断程序实现部分就在这个区程序运行区依不同的程序而不用。
2.2.3 640K~1M之间这期间有些地方是ROM,有些地方是硬件的BIOS区我僅以两个例子说明这一区。
ROM区:ROM区就是只读内存也就是说这个区的数据只能读不能写。比如F000:0000开始的内存是ROM我们来写一下,然后再看看效果
-d f000: '再次显示这个区的数据。
通过上面测试发现该区数据仍然未改变。但你要是试别的RAM区的肯定会变。如果想试你自己试试吧
显礻缓冲区:在文本方式下,B800:0000开始的地址保存着屏幕上每个字符位置的值在文本方式下,屏幕被分为80 X 25每个位置有两个值,一个值是ASCII字符一个值是该ASCII的属性值(主要是颜色)。所以一个屏幕共有80X25X2=400个字符
-d b800: '显示屏幕缓冲区的内容,注意此时本行最左边的“-”是屏幕左上角
現在修改这些值。我把左上角的字改成黄颜色的“-”那当然是改b800:0001的属性值了。
是不是左上角的颜色变成黄色了吗
好了,把第二个字符變成绿色的“-”吧
3.1 什么是机器语言
前面提到“最早的计算机采用机器语言,这种语言直接用二进制数表示通过直接输入二进制数,插拔电路板等实现这种“编程”很容易出错,每个命令都是通过查命令表实现”
比如要执行21号中断,需要查表得到21号中断的指令就是CD 21。这样不管你通过什么方式在内存指令位置,写入两个字节一个是CD(这可不是音乐光盘,而是二进制数转成十进制就是205),另一个昰21(同样是十六进制十进制是33)。
3.2 什么是经典汇编程序100例语言
前面也提到“既然是通过“查表”实现的那当然也可以让计算机来代替囚查表实现了。于是就产生了经典汇编程序100例语言”经典汇编程序100例语言产生的重要目的就是用容易记的符号来代替容易出错的二进制數(或十六进制数)。
比如前面的21号中断机器语言是CD 21。而经典汇编程序100例语言就规定中断用int表示(interrupt的前三个字母)21号中断就成了int 21h。其Φ21后面的h表示是表示这个21是十六进制由于大小写不敏感,所以int 21h写成下列方式都等价:
───────────────────────────────────────
DAA 加法的十进制调整.
CMP 比较.(两操作数作减法,仅修改标志位,不回送结果).
DAS 减法的十进制调整.
以上两条,结果回送AH和AL(字节运算),或DX和AX(字运算),
商回送AL,余数回送AH, (字节运算);
CBW 字节转换为字. (把AL中字节的符号扩展到AH中去)
CWD 字转换为双字. (把AX中的字的符号扩展到DX中去)
CWDE 字转換为双字. (把AX中的字符号扩展到EAX中去)
CDQ 双字扩展. (把EAX中的字的符号扩展到EDX中去)
───────────────────────────────────────
TEST 测试.(两操作数作与运算,仅修改标志位,不回送结果).
RCL 通过进位的循环左移.
RCR 通过进位的循环右移.
以上八种移位指令,其移位佽数可达255次.
移位>1次时, 则由寄存器CL给出移位次数.
───────────────────────────────────────
1>无條件转移指令 (长转移)
JMP 无条件转移指令
以上四条,测试无符号整数运算的结果(标志C和Z).
以上四条,测试带符号整数运算的结果(标志S,O和Z).
JNC 无进位时转移.
JNO 鈈溢出时转移.
JP/JPE 奇偶性为偶数时转移.
3>循环控制指令(短转移)
5>处理器控制指令
HLT 处理器暂停, 直到出现中断或复位信号才继续.
WAIT 当芯片引线TEST为高电平时使CPU进入等待状态.
ESC 转换到外处理器.
STC 置进位标志位.
CLC 清进位标志位.
CMC 进位标志取反.
STD 置方向标志位.
CLD 清方向标志位.
STI 置中断允许位.
CLI 清中断允许位.
───────────────────────────────────────
3.4 再谈寄存器和内存的区别
第零讲说到“寄存器在CPU中内存茬内存条中。前者的速度比后者快100倍左右后面的程序要求每条指定要么没有内存数据,要么在有一个寄存器的参与下有一个内存数据(也就是说,不存在只访问内存的指令)”
寄存器是在CPU中的存储器,而内存是在内存条中的存储器CPU访问寄存器,只需要通过微指令直接就可以访问而访问内存则要先经过总线,再由总线到达内存控制器读到某单元的内存数据后放上总线,再传到CPU中CPU才能使用。
8086系列計算机的寄存器共有14个,每个都是十六位的
其中前四位,每个可以单位再分成两个AX=AH+AL,BX=BH+BLCX=CH+CL,DX=DH+DL这些分开的每个都是8位的。
这个分开不偠理解成平时语言中的分开你可以理解为AX是由AH和AL组合成的,你给AL付值就意味着同时给AX的低半部付值。你给AX付值就意味着同时改变AH和AL。这样作的好处是你可以更灵活地控制这个寄存器
看了3.3的指令集和3.4的寄存器,是不是已经了或者了?不要急上面的东西虽然多,我吔没让你一下学会(其实有些永远也不会似乎也不是什么大不了的事)。为了应付看的懂我后面所说的我把其中的指令挑几个重点的,你必须要记住其它的慢慢学吧。
注意不是move这个指令是把B中的数据复制给A,(B中仍保存原状)这里的A和B可以是寄存器,可以是内存但可以同时是寄存器,不能同时是内存比如
mov ax,100 ;这是对的,注意100在这里叫立即数但这个数在编译系统编译成exe的时候保存在内存中。如果学过别的高级语言你就可以理解为这就是赋值语句 Let ax=100/ax:=100;/ax=100。
伪指令就是不是真的指令但他同时又是指令。之所以说这样矛盾的话是因为偽指令不是机器语言的一部分,而是经典汇编程序100例语言的一部分是你告诉经典汇编程序100例的编译系统如何去作。
上面一行指令中DB就昰伪指令,他的作用就是告诉编译程序把后面一些数据或字符串放到内存中。当然对于exe来说已在内存中了,就不用“告诉”了(这僦是为什么叫伪指令)。string是你给这段内存起的名字如果你不需要这段内存,不起名字也可以但如果后面要用,当然要加上这个名字'這是我的第一个经典汇编程序100例语言程序$'这个就是要处理的数据,当然你也可以换成别的内容但需要注意的是,要以'$'结尾这是经典汇編程序100例的约写,即:只是到了$就认为字符串结束,否则就一直向下找直到找到一个$为止。所以这就要求你的字符串中不能有'$'如果必须有,再换别的处理方式后面再说。
前面已经定义了string后面要把地址找到,就要用到lea指令lea是把字符串的地址给A这个寄存器中,A当然鈳以上前面提到的任意寄存器注意地址和内容的区别。如果是内容就是把string的字符串给A了(当然这也不成立,一个字符串有很多字节洏一个寄存器只有两个字节)。
那么从上面也看到了string代表一个地址,lea把这个地址给了A那这个地址到底在哪里呢?事实上这不重要就潒你要把某书店买书,这个书店在哪并不是最重要的有没有你要的书才是最重要的。所以你前面标出string后面引用就行了,至于这个地址箌底在哪是编译程序的事不是你的事。
这个很容易理解吧寄存器A加上N,把和仍存在A中类似于高级语言中的let a=a+n/a:=a+n/a+=n。
记住串操作指令表面很複杂其实很简单。
因为他就象一个复杂的数学公式一样简单你所要记住的就是公式的格式,使用时具体套用即可
从一个地址到另一個地址的复制需要注意的是:
*把源串段地址给DS。
*把目的串段址给ES
*把目的串偏址给DI。
*把要复制的个数给CX这里可不考虑$了。
*把FLAG中的方向标誌标志你要的方向一个是顺向,另一个是逆向
记住:无条件转移指令 jmp。等于转 jz不等于时转jnz
int 中断号,注意进制默认是十进制,所以┿六进制就加h
好了,上面的指令变成七八个了这你不能嫌多了吧,如果再嫌多就不要继续向下看了
data SEGMENT '数据段,编程者可以把数据都放箌这个段里
'数据格式是: 标识符 db/dw 数据
edata SEGMENT '附加数据段,编程者可以把数据都放到这个段里
上面就是一个程序的框架结构在这个结构中,有彡个段DS,ESCS。这三个段分别存数据附加数据,代码段
开始编写我们的第一个程序。
程序要求:显示一个“Hello,Mr.286.”怎么样
1 要显示一个字苻串,根据前面我让你们记的七八个指令够吗答案是:不仅够,而且还用不完
首先定义一下总可以吧。
2 首先要考虑的问题就是找中断找到合适的中断,该中断就能帮我们完成这个显示任务我找到(在哪找到的,怎么找到的别问我,到网上或书上都能找到):
——————————————-
功能描述: 输出一个字符串到标准输出设备上如果输出操作被重定向,那么将无法判断磁盘已满
DS:DX=待输出芓符的地址
说明:待显示的字符串以’$’作为其结束标志
——————————————-
由上面看到,我们所需要作的就是把DS指向数据段DX指向字符串的地址,AH等于9H,调用21h中断
由于只要在调用int 21h之前把准备的东西准备齐就行了,所以int 21h前面三行的顺序并不重要
3 退出程序,运行唍总要退出呀再查中断手册
——————————————–
功能描述: 终止程序的执行,并可返回一个代码
——————————————–
这里需要说明的是返回代码有什么用返回给谁?返回给操作系统因为是操作系统DOS调用的这个程序,这个返回值可以通过批处悝中的errorlevel得到这里不多说明,实际上操作系统很少处理这一值因此al你随便写什么值影响都不大。
把上面程序保存成hello286.asm后就可以编译运行叻。进入DOS进入经典汇编程序100例目录,如果还没下载到前面找下载地址。
说明:上面连续三个回车表示我要的都是默认值。下面是零個警告零个严重错误,(当然了我的程序还敢错吗?)
说明:三个回车仍要默认后面有个警告,没有栈段这个没关系,没有的话系统会自动给一个()
——————————————————————————
上面是什么呀?还记得前面说的吗?
段址:偏址 机器語言 mov指令 把段地址的地址(141f)赋值给AX寄存器
后面的是垃圾数据,不用管它把上面程序与源程序作一个比较,看有什么不用差别在于把标號语言转成实际地址了。
程序前两行一执行数据段地址就变成了141f,而那个字符串偏移地址在0000由(LEA DX,[0000]看出),所以我用-d 141f:0000 L20(后面L20表示只显示20個字节)就能把段地址显示出来了。
所以刚才的程序在内存中就变成了:
刚刚学习了经典汇编程序100例语言发现寻址方式非常重要,于昰做了一个小总结请各位笑纳。
1.指令集:cpu能够执行的指令的集合
2.指令:cpu所能够执行的操作。
3.操作数:参加指令运算的数据
4.寻址方式:在指令中得到操作数的方式。
现在就重点讨论寻址方式说白了也就是cpu怎么样从指令中得到操作数的问题。另外再强调一点操作数还分種类:
1)数据操作数:全都是在指令当中参加操作的数据
1.立即操作数:它在指令中直接给出。
2.寄存器操作数:它被放到寄存器中
3.存储器操作数:当然在存储器也就是内存中。
4.i/o操作数:它在你给出的i/o端口中
2)转移地址操作数:在指令当中不是参加运算或被处理的数据了,而是转移地址
还可以按照下面分类方式:
源操作数都是指令当中的第2个操作数,在执行完指令后操作数不变而目的操作数是指令当Φ的第1个操作数,在执行完操作指令后被新的数据替代
我们就围绕这几种操作数,也就是操作数所在的位置展开讨论
先说数据操作数,它分3大类共7种
1)立即数寻址方式:是针对立即操作数的寻址方式。在指令当中直接给出它根本就不用寻址。
在这里1234h和5678h都是立即操作數在指令当中直接给出。
2)寄存器寻址方式:是针对寄存器操作数的寻址方式它在寄存器中我们就用这中方式来找到它。
在这里axbx,ds嘟算是寄存器寻址例1中的ax也是寄存器寻址方式。
3)存储器寻址方式:针对在内存中的数据(存储器操作数)都用这种方式来寻找一共囿5种(这是我自己的说法,便于记忆)
不得不提及以下的概念:由于的字长是16bit,能够直接寻址2的16次方也就是64kb而地址总线是20bit,能够直接尋址2的20次方也就是1M空间所以把内存分为若干个段,每个段最小16byte(被称为小节)最大64kb,它们之间可以相互重叠这样一来内存就被分成鉯16byte为单元的64k小节,cpu就以1小节为单位寻址:在段寄存器中给出段地址(16bit)在指令当中给出段内偏移地址(16bit),然后把段地址左移4bit再与偏移哋址求和就得到数据在内存当中的实际物理地址了因而可以找到数据。
1.存储器直接寻址方式:在指令当中以 [地址] 的方式直接给出数据所茬内存段的偏移地址
在这里[1234h]和VALUE就是在指令中直接给出的数据所在内存段的偏移地址(16bit)。
VALUE是符号地址是用伪指令来定义的,它代表一個在内存中的数据(也就是它的名字)es:是段前缀符,用来指出段地址在这之前应该将段地址添入段中,本例中是es默认是ds,也就是不需给出应该注意 [地址] 与立即寻址的区别,在直接给出的数据两边加 [] 表示存储器直接寻址以区别立即寻址。另外 VALUE=[VALUE]
2.寄存器间接寻址:不昰在指令中直接给出数据在内存中的偏移地址,而是把偏移地址放到了寄存器中
这里[bx]就是寄存器间接寻址,bx中应方入段内偏移地址其Φ:若使用bx,si,di默认段地址为ds,若使用bp则默认段地址为ss并且允许段跨越,也就是加段前缀符注意:在寄存器两边加 [] 以与寄存器寻址区别。
3.寄存器间接相对寻址:偏移地址是bx,bp,si,di中的内容再与一个8bit或16bit 的位移量之和
4.基址变址寻址:偏移地址是一个基址寄存器和一个变址寄存器内容嘚和,既:bx或bp中的一个与si或di中的一个求和而得到
上面[bx+si]和[bp+di]都是基址变址寻址。若使用bx做基址寄存器则默认段地址为ds若使用bp为基址寄存器則默认段为ss,允许段跨越
5.基址变址相对寻址:偏移量是一个基址寄存器一个变址寄存器只和再与一个8bit或一个16bit位移量只和得到。
[bx+si]+12h和[bp+di]+1234h就是基址变址相对寻址若使用bx做基址寄存器则默认段是ds,若使用bp做基址寄存器则默认段为ss允许段跨越。
下面是转移地址操作数的寻址方式:
1.段内直接短转移:cs(代码段)内容不变而ip(指令指针寄存器)内容由当前ip内容+(-127~127),在指令中直接给出
其中,short是段内短转移的操作苻用以指出是转移到当前位置前后不超过±127字节的地方。而NEW_ADDR是要转移到的符号地址它的位置应该在当前ip指针所在偏移地址不超过
±127的哋方。否则语法出错
2.段内直接近转移:cs内容不变,而ip内容由当前ip内容+(-32767~32767)在指令中直接给出。
其中near ptr是段内近转移的操作符用以指絀转移到当前位置前后不超过±32767的地方。NEAR_NEW_ADDR是要转移到的符号地址
2)段内间接转移:cs的内容不变,而ip的内容放在寄存器中或者存储器中给絀
这种寻址方式是在寄存器或存储器中找到要转移到的地址,而地址是16bit的因而寄存器必须为16bit,如:bx我们用word ptr来指定存储器单元也是16bit的。注意:它是间接的给出只能使用类似于数据操作数中的除立即寻址以外的6种寻址方式(就在上面)。
3)段间直接寻址:cs和ip的内容全都變化由指令当中直接给出要转移到的某一个段内的某一个偏移地址处。
1234h送入cs中作为新的段地址5678h送入ip中作为新的偏移地址。far ptr是段间直接轉移操作符NEW_ADDR是另外一个段内的偏移地址,在这个指令中把NEW_ADDR的段地址送入cs(不用你给出)把它的段内偏移地址送入ip中作为新的偏移地址。
4)段间间接寻址:cs和ip的内容全变化由指令当中给出的一个4字节连续存储单元,其中低2字节送入ip作为偏移地址高2字节送入cs作为段地址。
dword ptr是双字(4个字节连续存储单元)操作符用来指出下面的存储单元是4个字节的。由于它是4个字节的所以只能使用类似于数据操作数中嘚存储器寻址方式(共5种,还记得吗)。
另外作为特殊的寻址方式还有三种:I/O寻址串寻址,隐含寻址它们都分别针对I/O指令,串操作指令以及无操作数的指令而且都比较简单,读者自行总结
到此为止说明了cpu中的所有寻址方式,我这里只是个总结具体的细节还要大镓自己钻研课本,才能理解
写的有些仓促可能有些遗漏或错误,还请谅解