马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 兰陵月 于 2017-12-5 21:56 编辑
第1部分 预备知识 第1章 十六进制计数法 1.1 二进制计数法回顾 【1.1.1 关于二进制计数法】 在计算机里用高低两种电平的组合来表示数字。一般情况下,高电平表示1,低电平表示0。 从数学的角度看,二进制计数法是现代主流计算机的基础。一方面,它简化了硬件设计。因为它只有两个符号,要得到它们,可以用最少的电路元件来接通或者关断电路就行了。另一方面,二进制数与我们熟悉的十进制数之间有着一对一的关系,任何一个十进制数都对应着一个二进制数,不管它有多大。 组成二进制数的每一个数位,称为一个比特(bit),而一个二进制数可以看成是一个比特串。很明显,它的数值越大,比特串就越长,这是二进制计数法不好的一面。 【1.1.2 二进制到十进制的转换】 每一种计数法都有自己的符号(数符)。十进制有0、1、2、3、4、5、6、7、8、9十个符号,二进制只有0、1两个符号。这些数字符号的个数称为基数。也就是说,十进制有10个基数,而二进制只有两个基数。 二进制和十进制都是进位计数法。进位记数法的一个特点是,符号的值和它在这个数中所处的位置有关。比如十进制数356,数字6处在个位上,所以是“6个”;5处在十位上,所以是“50”,3处在百位上,所以是“300”。即: 百位3、十位5、个位6=3×102+5×101+6×100=356 这就是说,由于所处的位置不同,每个数位都有一个不同的放大倍数,这称为“权”。每个数位的权是这样的计算的(这里仅讨论整数):从右往左开始,以基数为底,指数从0开始递增的幂。正如上面的公式所清楚表明的那样,“6”在最右边,所以它的权是以10为底,指数为0的幂100;而3的权是以10为底,指数为2的幂102。 数字后面紧跟大写的B,表示这是一个二进制数。紧跟大写的D表示这是一个十进制数。“B”和“D”分别是英语单词Binary和Decimal的头一个字母,这两个单词分别表示二进位和十进位的意思。[20170912] 【1.1.3 十进制到二进制的转换】 为了将一个十进制数转换成二进制数,可以采用将它不停地除以二进制的基数2,直到商为0,然后将每一步得到的余数按先后顺序从右至左串起来,就是我们所要转换的二进制数。[20170913] 1.2 十六进制计数法 【1.2.1 十六进制计数法的原理】 二进制的缺点就是写起来太长,不方便。于是,人们发明了十六进制计数法。十六进制有十六个数符,分别是0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F。前面10个数符和十进制的10个数符是一样的,从A开始到F,分别对应十进制的10、11、12、13、14、15。在十六进制里,一旦某个数位增加到9之后,下一次,它将变成A,而不是直接进位。十六进制计数法是逢十六进位,因此只发生在某个数位原先是F的情况下,比如1F加1之后就变成20。 【1.2.2 十六进制到十进制的转换】 将1个十六进制数转换成十进制数的方法同前面,只是在计算权的时候,相应地把幂的底数换为16。比如将十六进制数125转换成十进制数的方法如下: 125H=1×162+2×161+5×160=293D 数字后面加“H”,表示这是一个十六进制数,H是英语单词Hexadecimal的头一个字母,这个单词的意思是十六进制。 【1.2.3 十进制到十六进制的转换】 把一个十进制数转换成十六进制数,可以采取不停地除以16,直到商为0,然后每次得到的余数按先后顺序从右至左排列,就得到所要转换的十六进制数。[20170917] 【1.2.4 为什么需要十六进制】 4比特的二进制数,可以表示的数是从0000到1111,也就是十进制的0~15,正好对应于十六进制的0~F。 如果将一个二进制数从右往左,分成4比特为一组的形式,分别将每一组的值转换成十六进制数,就可以得到这个二进制数所对应的十六进制数。 从事计算机的学习和研究,不可避免地要与二进制数打交道,而且有时候还必须针对其中某些比特进行特殊处理。这个时候,如果想保留二进制数的直观性,同时还要求写起来简短,十六进制数是最好的选择。[20170924] 第2章 处理器、内存和指令 2.1 最早的处理器 1947年,美国贝尔实验室的肖克利和同事们一起发明了晶体管。1958年,美国人杰克·基尔比发明了集成电路。1971年,在为日本人设计计算器芯片的过程中,受到启发的Intel公司生产了世界上第一个处理器INTEL 4004,设计者为弗德里科·法金。 处理器(Processor)是电子计算机的核心,它会在振荡器脉冲的激励下,从内存中获取指令,并发起一系列由该指令所定义的操作。当这些操作结束后,它接着再取下一条指令。通常情况下,这个过程是连续不断、循环往复的。 2.2 寄存器和算术逻辑部件 1byte=8bit 1word=2byte 1 double word=2 word 2.3 内存储器 对于个人计算机来说,内存按字节来组织,单次访问的最小单位是1字节,这是最基本的存储单元。内存中的每一个字节都对应着一个地址。 为了访问内存,处理器需要给出一个地址。访问包括读和写。因此在访问的时候,处理器还要指明,本次访问是读访问还是写访问。如果是写访问,则还要给出待写入的数据。 尽管内存的最小组成单位是字节,但是,经过精心的设计和安排,它能够按字节、字、双字和四字节进行访问。意思就是说仅通过单次访问就能处理8位、16位、32位或者64位的二进制数。 处理器发出字长控制信号,以指示本次访问的字长是8、16、32还是64。 2.4 指令和指令集 设计处理器的目标之一就是使它成为一种可以自动进行操作的器件。同时,处理器的设计者用某些数字来指示处理器所进行的操作,这称为指令,或者叫机器指令。 一般来说,指令由操作码和操作数构成,但也有小部分指令仅有操作码,而不含操作数,比如F4H(停机指令)。指令的长度不定,短的指令仅有1字节,而长的指令则有可能达到15字节(对于INTELx86处理器来说)。 对处理器来说,指令的操作码隐含了如何执行该指令的信息,比如它是做什么的,以及怎么去做。 操作数紧跟在操作码之后,可以立即从指令中取得,所以叫做立即数,立即数已经在指令中给出,不需要再次访问内存。 低端字节序,它规定高字节位于高地址部分,低字节位于低地址部分。反之称为高端字节序。 指令和数据要分开存放,分别位于内存中的不同区域,存放指令的区域叫代码区,存放数据的区域叫做数据区。 一个处理器能够识别的指令的集合,称为该处理器的指令集。 2.5 古老的Intel8086处理器 8086是Intel公司第一款16位处理器,诞生于1978年,所以说它很古老。是整个Intel32位架构处理器(IA-32)的开山鼻祖。 【2.5.1 8086的通用寄存器】 8086处理器内部有8个16位的通用寄存器,分别是AX、BX、CX、DX、SI、DI、BP、SP。通用的意思是它们之中的大部分都可以根据需要用于多种目的。 其中,AX、BX、CX、DX又可以分别分开为8位的寄存器,分别是AH、AL、BH、BL、CH、CL、DH、DL。 当一个16位的寄存器当成两个8位的寄存器来用时,对其中一个8位寄存器的操作不会影响到另一个8位寄存器。 【2.5.2 程序的重定位难题】 为了让程序在内存中的任何位置正确执行,在编写程序时只能使用相对地址或者逻辑地址,而不能使用真实的物理地址。 8086处理器用分段机制解决程序重定位问题。 【2.5.3 内存分段机制】 段可以开始于内存中的任何位置,段内的每一个单元相对段的起始地址有一个相对差,叫做偏移地址。 于是,采用分段机制之后,一个内存单元的地址可以采用“段地址:偏移地址”来表示。 为了在硬件一级提供对“段地址:偏移地址”内存访问模式的支持,处理器至少要提供两个段寄存器,分别是代码段寄存器CS和数据段寄存器DS。对CS内容的改变将导致处理器从新的代码段开始执行。同样,在开始访问内存中的数据之前,也必须首先设置好DS寄存器,使之指向数据段。 最重要的是,当处理器访问内存时,它把指令中指定的内存地址看成是段内的偏移地址,而不是物理地址。这样,一旦处理器遇到一条访问内存的指令,它将把DS中的数据段起始地址和指令中提供的段内偏移相加,来得到访问内存所需要的物理地址。当下一次这个程序执行时,如果代码段和数据段在内存中的位置发生了变化,只要把它们的段地址分别传送到CS和DS,它也能够正确执行。 【2.5.4 8086的内存分段机制】 8086内部有4个段寄存器,分别是CS、DS、ES、SS。 IP是指令指针寄存器,它只和CS一起使用。 16位的段地址和16位的偏移地址相加,只能得到16位的物理地址。但是8086处理器提供了20根地址线,可以访问多大1M的内存。因此为了形成20位的地址,8086在形成物理地址时,先将段寄存器的内存左移4位(相当于乘以十六进制的10,或者十进制的16),形成20位的段地址,然后再同16位的偏移地址相加,得到20位的物理地址。 因为段寄存器是16位的,在段不重叠的情况下,最多可以将1MB的内存分成65536个段,每个段正好是16个字节。同样在不允许段之间重叠的情况下,每个段的最大长度是64KB,因为偏移地址也是16位的,从0000H到FFFFH。在这种情况下,1MB的内存,最多只能划分成16个段,每段长64KB。 程序员的任务是定义段地址并设置处理器的段寄存器,其中最重要的是段地址的选取。 段的划分是自由的,它可以起始于任何16字节对齐的位置,也可以是任意长度,只要不超过64KB。 同一个物理地址,实际上对应着多个逻辑地址。 第3章 汇编语言和汇编软件 3.1 汇编语言简介 为了克服机器指令难以书写和理解的缺点,人们想到可以用一些容易理解和记忆的符号,也就是助记符,来描述指令的功能和操作数的类型,这就产生了汇编语言(Assembly Language)。 MOV是传送指令,需要两个操作数,分别是目的操作数和源操作数。它们之间要用逗号隔开。【汇编语言对指令的大小写没有特别的要求。】 在很多高级语言中,如果要指示一个数是十六进制数,通常不采用在后面加“H”的做法,而是为它添加一个“0x”前缀。 用汇编语言提供的符号书写的文本,叫做汇编语言源程序。但是汇编语言源程序是机器无法识别的,因此要将汇编语言源程序转换成机器指令,这个过程叫做编译。编译肯定还需要一个软件,称为编译器,或编译软件。汇编语言源程序经过编译之后,会生成二进制文件或者可执行文件。 3.2 NASM编译器 【3.2.1 NASM的下载和安装】 NASM编译器全称是Netwide Assembler,它是可免费使用的开源软件。 【3.2.2 代码的书写和编译过程】 【3.2.3 用HexView观察编译后的机器代码】 |