汇编语言入门
三大类语言——汇编语言系列
汇编语言,总给人一中乱七八糟的东西整到一起,然后就出来了。事实上,汇编语言和此
还真有点儿相像。那什么是汇编语言呢?
计算机的编程语言经历了三大过程:
一、机器语言
计算机说白了就是对电信号的处理,计算机的电信号就是高电位和低电位两种,就是通和断。我们把通记作1,断记作0。所以,有人说计算机脑子笨,只会数到1。事实上,这已经足够了。最开始的编程可不像现在这么轻松。1001010101010000110就可能是一段指令(就是命令CPU做一个事情的最基本单元),但是,这实在是太费劲了。计算机读得懂,可人
读不懂啊!我真怀疑前辈是怎么熬过来的。
二、汇编语言
不知道那位天才的主意,他把这些难懂的计算机指令转换为通俗易懂的英语单词简写。比如说用的最多的10指令,它的作用就是把数据挪来挪去的,所以和英语单词move的意思
差不多,干脆,把它替换成MOV吧。这样,每个难懂的计算机指令都转换成为了指令
助记符(确实挺好记忆的)。然后,再由汇编器将汇编源代码翻译成机器语言。最开始的翻译就是一就是1,二就是2。现在的汇编器功能越来越全,以至于兼容了高级语言的语法,各种语法格式的汇编层出不穷,但是,最低级(这只是相对底层的说法)的还是Intel语法。
三、高级语言
虽然汇编语言令人轻松了不少,不过还是不接近人的思维。所以,高级语言又诞生了。比较有名的高级语言,比如C语言,就兼有高级低级两大特征。既有符合人类的思维方式,又可以和汇编语言进行轻松的转换,汇编味道还是很浓的。编译C语言有这么几个步骤:1、使用C编译器编译成汇编语言格式;2、使用汇编器编译成二进制可执行程序格式。所以,C语言一直是编写操作系统的首选语言(和汇编并列)。像VB这样的语言,就没有汇编味道了。
举个例子,下面是C语言的代码(我相信你学过C语言,如果没有学过,以后学吧):
if(!a) return; //如果a等于0,就返回,否则a=1
a=1;
可以直接转化为汇编语言:
cmp ax, 0 ;AX中是数据a
jnz nequ_zero ;如果不等于0就调到nequ_zero
ret        ;返回,相当于return
nequ_zero:
mov ax, 1  ;ax为1
怎么样,C语言是不是兼容高低两种风格?
我们已经初步地接触了一下汇编语言,感觉怎么样?看不懂?没关系,我们刚刚接触它,还什么都没有学呢。大家只是先有一个感性的认识。好了,先写道这里吧!
CPU的寄存器——汇编语言入门
为什么不直接讲汇编语言,而先讲CPU寄存器呢?因为,汇编指令对它们的操作是最频繁的,如果不知道它们是干什么的话,怎么能学会汇编语言呢?
我们知道,数据交换方面,CPU内部数据交换最快,其次是内存,最慢的是什么光驱软驱硬盘什么的。在CPU中,就有一个个的小单元,用来暂时储存一些数据,就好像车站的寄存处一样,所以,它们有一个名称,叫CPU寄存器(简称寄存器)。这些寄存器都是:4个16位数据寄存器,2个16位指针寄存器,2个16位变址寄存器,2个16位控制寄存器,4个16位段寄存器。
一、通用寄存器:数据寄存器、指针寄存器、变址寄存器的总称。这些寄存器除了各自的用途外,都可以暂时存储数据、内存地址和运算结果。
1、数据寄存器:数据寄存器指AX、BX、CX和DX。这里的AH是AX的高字节,AL是AX的低字节(High和Low),其他的数据寄存器同理。这些数据寄存器的用途稍微有一点不同。
1)AX(Accumulator)寄存器,又叫累加器。用来存储乘法结果和除法结果,I/O数据。也可以用来做它用。同时,也通常进行加减法,所以叫做累加器。AX寄存器的使用频率最高,用途很广。
2)BX(Base)寄存器,又叫基地址寄存器(基址寄存器),用来存储内存地址。这是数据寄存器中唯一可用于存储器指针的寄存器。
3)CX(Counter)寄存器,又叫计数器。用来控制循环的次数。
4)DX(Data)寄存器,又叫数据寄存器,进行32位除法时,用来存放被除数的高16位和余数。也用作I/O端口地址。
2、指针寄存器和变址存储器:是指BP、SP、DI和SI,用来存储在段中的偏移地址(首次接触偏移地址,可能不太明白,不要紧,后面会讲的),我们把内存想象成一条街道,这条街道分成一部分一部分的(段),每部分的每家每户都有一个相对于这个部分开头的地址(偏移地址),比如你在平安街,
平安街分为西平安街和东平安街,你家住在西平安街(段地址)31号(偏移地址)。
1)BP(Base)寄存器,又叫基地址指针寄存器。用来存储在段中的偏移地址。
2)SP(Stack)寄存器,又叫堆栈指针寄存器。这个寄存器有些特殊,因为它和堆栈紧紧相关。什么是堆栈呢,请看后面的段寄存器。
3)DI和SI寄存器,又叫目的地址寄存器和源地址寄存器。用来进行串操作。说一下串操作,假设把内存中一串连续的数据从这里挪到那里,怎么办?能够想到的是,把这一串连续的数据中第一个数据在内存中的地址(源地址)移到一个寄存器中(比如SI),然后把要到的地方在内存中的地址(目的地址)移到另一个寄存器中(比如DI)。然后把SI所指的数据挪到AX,再把AX中的数据挪到DI所指的地方。让SI和DI指向下一个数据。这种操作叫做串操作,就是把一串连续的数据挪到另一个连续的内存处。
二、控制寄存器,这些寄存器比较特殊,不能够存储数据。
1、IP寄存器,指向当前运行到的代码的内存偏移地址。
开始的时候,IP指向内存中的一个指令。然后,CPU根据IP中的内存地址,把这个指令读取进来,并执行。同时,IP指向下面的一个指令,就回到了步骤1,这样不断地执行下去,就是一步一步的。排除有指令缓存的情况。
2、标志寄存器:
有些指令会影响标志,有些指令不会影响标志,而有些指令受标志影响,有些指令不受标志影响。这些标志可以分为两组,一组主要受加减乘除运算影响,成为运算结果标志,另一些成为控制状态标志。
汇编语言如何编程
运算结果标志:
1)CF(Carry):进位标志,反应运算是否有进位和借位,有则为1,没有为0。有时作函数的出口参数。
2)ZF(Zero):零标志,运算结果为0则置位为1,运算结果不为零则复位为0。
3)SF(Sign):符号标志,反应运算结果的符号位。SF于运算结果的最高位(即符号位)相同。在80x86中,有符号数采用补码的形式表示,所以SF反映了运算结果的符号。如果运算结果为正,则SF为0,否则为1
4)OF(Overflow):溢出标志,用于反应有符号数运算是否引起溢出。如果运算结果超出了8位或16位有符号数的表示范围,即在字节运算时大于127或小于-128,字运算时大于32767或小于-32768,称为溢出,则OF被置1。
5)PF(Parity):奇偶标志,用于反应运算结果中“1”的个数,如果,“1”的个数为偶数,则PF置1,否则清0。
6)AF(Auxiliary Carry):辅助进位标志:在字节操作时,如发生低半字节向高半字节进位或借位;在字操作时,如发生低字节向高字节进位或借位,则AF被置1,否则清0。
2、状态控制标志
1)DF(Direction)方向标志,当DF为1时,串操作指令按递减方式改变有关存储器指针值;当DF为0时,串操作指令按递加方式改变有关寄存器值。设置DF方向为的指令为STD(Set Deriction),清除指令为CLD(Clean Direction)
2)IF(Interrupt)中断标志,当IF为1时,允许可屏蔽中断产生,当IF为0时,屏蔽任何可屏蔽中断。设置IF为1的指令是STI(Set Interrupt),设置IF为0的是CLI(Clean Interrupt)。
3)TF(Trap)追踪标志,当TF被置位1后,CPU进入单步方式。所谓单步方式,就是执行一条指令就产生一个单步中断,用于程序的调试。
三、段寄存器。这里应用了分段机制,80x86把一兆的内存(16位模式下只支持一兆)分为一个个的段,每个段寄存器就存储相应的段基地址。CS(Code Segment)代码段基址寄存器;DS(Data Segment)数据段基址寄存器;ES(Extra Segment)附加断寄存器;SS(Stack Segment)堆栈段寄存器。
至于分段机制的具体内容,将在以后的文章中介绍。
内存寻址和分段机制——汇编语言入门
上一篇文章介绍了CPU的寄存器,不知道大家留意到没有,这几个寄存器有一些特殊,SI/DI/SP/BP,这几个寄存器都有指针这个词,那什么是指针呢?CS/DS/ES/SS叫做段寄存器,什么又是段呢?为什么要出现分段机制?
一、什么是指针
内存,如果安装编程的眼光看的话,就是一连续的存储空间,这里,最小的存储空间是位(这个概念不用解释吧),但是,位实在是太小了,所以,内存空间被分为1字节
1字节的,也就是把1字节作为一个单位。如果我们把内存空间比作一条街的话,这每一个单位就是一个楼。可是,我如何知道我需要的是哪个楼呢?我们知道,要某一号楼的话,一般说这是XX街64号楼,这叫地址。内存中每个单位也有一个地址,叫内存地址。内存
地址是从0开始计数的。内存中第一个字节的内存地址是0x0000(这是十六进制)什么是十六进制,我就不再说明了。第二个字节的内存地址是0x0001。存储这些内存地址的寄
存器就叫指针寄存器,指针,就是指着这一个内存单元的“针”,说白了就是一个内存地址。
二、什么是分段机制
我们知道,16位的PC机上,内存寻址最远的是0xFFFF(1111111111111111),这是靠单一十六位寻址的最大范围了。但这实际上并不大,才能寻址到64KB的地方,这实在是
太小了。(怎么算的64KB)使用Windows自带的计算器,调整到科学型,选择[十六进
制],输入FFFF,然后加1,因为内存地址是从0算起的,得出的就是寻址的最远处,这时的数是10000,表示最远到0x10000字节处,不够直观,必须除以400(十六进制的),(我们知道,KB到B的换算是1024,十六进制的表示就是400)得到40(还是十六进制的),再选择十进制,就是64,也就
是64KB。
确实太小了,怎么办呢?于是引入了段的概念,一个内存地址就由“段基址:段内偏移地址”表示。段基址,就是这个段的起始地址;段内偏移地址,就是距段基址的距离。这样,段内偏移地址最大是0xFFFF,所以,一个段的最大长度是64KB。那怎么把这个内存地址换算成最基本的内存地址呢?规则是这样的:
实际内存地址=段基址×0x10+段内偏移地址
我们看一看,段基址最大是0xFFFF,段内偏移地址最大是0xFFFF,所以有:
0xFFFF×0x10+0xFFFF=0xFFFF0+0xFFFF=0x10FFEF
大约是1M,这可比64KB大多了。
那么,一个内存地址就有两种表示方法了:0:0x1000=0x100:0
也就是说,段基址是0x0,段内偏移地址是0x1000,和段基址是0x100,段内偏移地址是0x0所指向的内存地址相同,不信你算一算。
你也许就知道了,CS/DS/ES/SS段寄存器存储的就是段基址。那么我们就可以用
DS:0x0002得到数据段中偏移地址为0x0002的数据。
这四个段寄存器是各有分工的。在取指令时,自动把CS×0x10+IP得出要取的指令。在进行堆栈操作时,自动把SS×0x10+SP得到栈顶指针。在进行普通数据操作时,自动把

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。