x86汇编语言:从实模式到保护模式 1-2章 学习笔记

本文介绍了二进制计数法和十六进制计数法在计算机中的应用,详细讲解了处理器、内存、指令的概念,以及寄存器、算术逻辑单元的作用。重点涉及8086处理器的寄存器结构和内存分段原理,展示了如何利用内存地址进行数据操作和程序控制。
摘要由CSDN通过智能技术生成

第1章

1、二进制计数法

二进制计数法是现代计算机的基础,组成二级制数的每一个数位,称为一个比特(bit),一个二进制数也可以看成是一个比特串。

2 、十六进制计数法

二进制数和计算机电路有着近乎直观的联系。电路的状态,可以用二进制数来直观地描述,而一个二进制数,也容易使我们仿佛观察到了每根电线上的电平变化。所以,我们才形象地说,二进制是计算机的官方语言。但是,二进制也有他的缺点,主要的缺点就是写起来太长,一点也不方便。这就出现了十六进制。
在这里插入图片描述
十六进制的每一位与二进制的每四位有着对应的关系。
正如前面所说的,从事计算机的学习和研究,不可避免地要与二进制数打交道,而且有时还必须针对其中某些比特进行特殊处理。这个时候,如果想保留二进制数的直观性,同时还要求写起来简短,十六进制数是最好的选择。

第2章 处理器、内存、指令

2.1 什么是处理器

处理器是一台电子计算机的核心,他会在振荡器脉冲的激励下,在内存中获取指令,并发起一系列由该指令所定义的操作。当这些操作结束后,接着取指令执行,通常情况下,这个过程是连续不断、循环往复的。处理器实际上是一块集成电路。

2.2 寄存器和算术逻辑单元

在这里插入图片描述
如图在处理器的四周有大量的引脚,可以接受外面输入的电信号,或者向外发出电信号。每一个引脚都有自己的作用。
假设要实现加法的运算:
第一:加数通过处理器的引脚送入处理器(代表这个数字的一组二进制电信号出现在内部线路,这一组电信号代表数字二进制数中的每一位)。
第二:必须用一个称为寄存器(Register)的电路锁住。之所以要这样做,是因为相同的引脚和线路马上还要用于输入加数。也正是因为这个原因,这些内部线路称为处理器内部总线。同样地,加数也要锁进另一个寄存器中。如图2-2所示,寄存器RA和RB将分别锁存参与运算的被加数和加数。此后,RA和RB中的内容不再受外部数据线的影响。
寄存器是双向器件,可以在一端接受输入并加以锁存,同时,它也会在另一端产生一模一样的输出。与寄存器RA和RB相连的,是算术逻辑单元,或者算术逻辑部件(Arithmetic Logic Unit,ALU),也就是图2-2中的桶形部分。它是专门负责运算的电路,可以计算加法、减法或者乘法,也可做逻辑运算。在这里,我们要求它做一次加法。
一旦寄存器RA和RB锁存了参与运算的两个数,算术逻辑部件就会输出相加的结果,这个结果可以临时用另外一个寄存器RC锁存,稍后再通过处理器数据总线送到处理器外面,或者再次送入RA或RB。
处理器内部有一个控制器(图中没有画出),在指令的执行过程中,它负责给各个部件发送控制信号,使各个部件在某个正确的时间点上执行某个动作。同时,它还负责决定在某个时间点上哪个部件有权使用总线,以免彼此发生冲突。处理器总是很繁忙的,在它操作的过程中,所有数据在寄存器里面都只能是临时存在一会儿,然后再被送往别处,这就是为什么它被叫做“寄存器”的原因。早期的处理器,它的寄存器只能保存4比特、8比特或16比特,分别叫做4位、8位和16位寄存器。现在的处理器,寄存器一般都是32位、64位甚至更多。
位数越多储存的字数越大:
在这里插入图片描述

2.3 内存储器

内存储器就是我们平常说的内存条,他是计算机内部最主要的存储器,通常只和处理器相连。、在这里插入图片描述

内存按字节来组织,单次访问的最小单位是1字节,这是最基本的存储单元。如图中所示,每个存储单元中,各位的编号分别是0~7。内存中的每字节都对应着一个地址,如图2-5所示,第1个字节的地址是0000H,第2个字节的地址是0001H,第3个字节的地址是0002H,其他以此类推。注意,这里采用的是十六进制表示法。作为一个例子,因为这个内存的容量是65536字节,所以最后一个字节的地址是FFFFH。为了访问内存,处理器需要给出一个地址。访问包括读和写,为此,处理器还要指明,本次访问是读访问还是写访问。如果是写访问,则还要给出待写入的数据。8位处理器包含8位的寄存器和算术逻辑部件,16位处理器拥有16位的寄存器和算术逻辑部件,64位处理器则包含64位的寄存器和算术逻辑部件。尽管内存的最小组成单位是字节,但是,经过精心的设计和安排,它能够按字节、字、双字和四字进行访问。换句话说,仅通过单次访问就能处理8位、16位、32位或者64位的二进制数。注意,是单次访问,而不是一个一个地取出每个字节,然后加以组合。

在这里插入图片描述

2.4指令和指令集

简单地说,处理器的设计者用某些数来指示处理器所进行的操作,这称为指令(Instruction),或者叫机器指令,因为只有处理器才认得它们。前面已经说了,处理器内部有寄存器和负责运算的部件,控制器“分析”一个个指令,然后确定在哪个时间点让哪些部件进行工作。比如,指令F4H表示让处理器停机,当处理器取到并执行这条指令后,就停止工作。指令是集中存放在内存里的,一条接着一条,处理器的工作是自动按顺序取出并加以执行。
如图2-6所示,从内存地址0000H开始(也就是内存地址的最低端)连续存放了一些指令。同时,假定执行这些指令的是一个16位处理器,拥有两个16位的寄存器RA和RB。一般来说,指令由操作码和操作数构成,但也有小部分指令仅有操作码,而不含操作数。如图2-6所示,停机指令仅包含1字节的操作码F4,而没有操作数。指令的长度不定,短的指令仅有1字节,而长的指令则有可能达到15字节(对于INTELx86处理器来说)。
在这里插入图片描述
对处理器来说,指令的操作码隐含了如何执行该指令的信息,比如它是做什么的,以及怎么去做。第一条指令的操作码是B8,这表明,该指令是一条传送指令,第一个操作数是寄存器,第二个操作数是直接包含在指令中的,紧跟在操作码之后,可以立即从指令中取得,所以叫做立即数(Immediate Operand)。同时,操作码还直接指出该寄存器是RA。RA是16位寄存器,这条指令将按字进行操作。所以,当这条指令执行之后,该指令的操作数(立即数)005DH就被传送到RA中。既然操作码中隐含了这么多的信息,那么,处理器就可以“知道”每条指令的长度。这样,当它执行第一条指令B85D00的时候,就已经知道,这是一个3字节指令,下一条指令位于3个字节之后,即内存地址0003H处。注意字数据在内存中的存放特点。地址0001H和0002H里的内容分别是5D和00,如果每次读一个字节,则从地址0001H里读出的是5D,从0002H里读出的是00。但如果以字的方式来访问地址0001H,读到的就会是005DH。这种差别,跟处理器和内存之间的数据线连接方式有关。对于Intel处理器来说,如果访问内存中的一个字,那么,它规定高字节位于高地址部分,低字节位于低字节部分,这就称为低端字节序

2.5、 8086处理器

8086处理器内部有8个16位的通用寄存器,分别被命名为AX、BX、CX、DX、SI、DI、BP、SP。“通用”的意思是,它们之中的大部分都可以根据需要用于多种目的。如图2-7所示,因为这8个寄存器都是16位的,所以通常用于进行16位的操作。比如,可以在这8个寄存器之间互相传送数据,它们之间也可以进行算术逻辑运算;也可以在它们和内存单元之间进行16位的数据传送或者算术逻辑运算。同时,如图2-7所示,这8个寄存器中的前4个,即AX、BX、CX和DX,又各自可以拆分成两个8位的寄存器来使用,总共可以提供8个8位的寄存器AH、AL、BH、BL、CH、CL、DH和DL。这样一来,当需要在寄存器和寄存器之间,或者寄存器和内存单元之间进行8位的数据传送或者算术逻辑运算时,使用它们就很方便。
在这里插入图片描述
我们知道,处理器是自动化的器件,在给出了起始地址之后,它将从这个地址开始,自动地取出每条指令并加以执行。只要每条指令都正确无误,它就能准确地知道下一条指令的地址。这就意味着,完成某个工作的所有指令,必须集中在一起,处于内存的某个位置,形成一个段,叫做代码段。事情是明摆着的,要是指令并没有一条挨着一条存放,中间夹杂了其他非指令的数据,处理器将因为不能识别而出错。
为了做某件事而编写的指令,它们一起形成了我们平时所说的程序。程序总要操作大量的数据,这些数据也应该集中在一起,位于内存中的某个地方,形成一个段,叫做数据段。
注意,我们并没有改变内存的物理性质,并不是真的把它分成几块。段的划分是逻辑上的,从本质上来说,是如何看待和组织内存中的数据。
段在内存中的位置并不重要,因为处理器是可控的,我们可以让它从内存的任何位置开始取指令并加以执行。这里有一个例子,如图2-8所示,我们有一大堆数字,现在想把它们加起来求出一个总和。
在这里插入图片描述
假定我们有16个数要相加,这些数都是16位的二进制数,分别是0005H、00A0H、00FFH、…。为了让处理器把它们加起来,我们应该先在内存中定义一个数据段,将这些数字写进去。数据段可以起始于内存中的任何位置,既然如此,我们将它定在0100H处。这样一来,第一个要加的数位于地址0100H,第二个要加的数位于地址0102H,最后一个数的地址是011EH。一旦定义了数据段,我们就知道了每个数的内存地址。然后,紧挨着数据段,我们从内存地址0120H处定义代码段。严格地说,数据段和代码段是不需要连续的,但这里把它们挨在一起更自然一些。为了区别数据段和代码段,我们使用了不同的底色。代码段是从内存地址0120H处开始的
第一条指令是A10001,其功能是将内存单元0100H里的字传送到AX寄存器。指令执行后,AX的内容0005H。
第二条指令是03060201,功能是将AX中的内容和内存单元0102H里的字相加,结果在AX中。由于AX的内容为0005H,而内存地址0102H里的数是00A0H,这条指令执行后,AX的内容为00A5H。
第三条指令是03060401,功能是将AX中的内容和内存单元0104H里的字相加,结果在AX中。此时,由于AX里的内容是00A5H,内存地址0104H里的数是00FFH,本指令执行后,AX的内容为01A4H。
后面的指令没有列出,但和前2条指令相似,依次用AX的内容和下一个内存单元里的字相加,一直到最后,在AX中得到总的累加和。在这个例子中,我们没有考虑AX寄存器容纳不下结果的情况。当累加的总和超出了AX所能表示的数的范围(最大为FFFFH,即十进制的65535)时,就会产生进位,但这个进位被丢弃。
在内存中定义了数据段和代码段之后,我们就可以命令处理器从内存地址0120H处开始执行。当所有的指令执行完后,就能在AX寄存器中得到最后的结果。
这里确实有一个难题。
在例子中,所有在执行时需要访问内存单元的指令,使用的都是真实的内存地址。比如A10001,这条指令的意思是从地址为0100H的内存单元里取出一个字,并传送到寄存器AX。在这里,0100H是一个真实的内存地址,又称物理地址。整个程序(包括代码段和数据段)在内存中的位置,是由我们自己定的。我们把数据段定在0100H,把代码段定在0120H。问题是,大多数时候,整个程序(包括代码段和数据段)在内存中的位置并不是我们能够决定的在这种情况下,你所运行的程序,在内存中被加载的位置完全是随机的,哪里有空闲的地方,它就会被加载到哪里,并从那里开始被处理器执行。所以,前面那段程序不可能恰好如你所愿,被加载到内存地址0100H,它完全可能被加载到另一个不同的位置,比如1000H。但是,同样是那个程序,一旦它在内存中的位置发生了改变,灾难就出现了。
内存分段: 当采用分段策略之后,一个内存单元的地址实际上就可以用“段:偏移”或者“段地址:偏移地址”来表示,这就是通常所说的逻辑地址。同一个物理地址可以有不同的逻辑地址。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值