一、CPU是什么
CPU的内部结构解析
程序是指令和数据的组合体;
CPU是能够直接识别和执行的只有机器语言,根据程序指令进行数据计算并控制整个计算机设备的元件;
硬盘和磁盘等媒介上保存的程序被复制到内存后才能运行;
内存地址是保存命令的和数据的场所;
CPU内部由寄存器、控制器、运算器和时钟构成,寄存器暂存指令、数据等处理对象,控制器负责把内存的指令和数据等读入寄存器,运算器负责运算从内存读入寄存器的数据,时钟发出CPU开始计时的时钟信号;
CPU是寄存器的集合体
汇编语言编写的程序转化成机器语言的过程称为汇编;
使用高级语言编写的程序会在编译后转化成机器语言,然后再通过CPU内部的寄存器来处理;
寄存器存储的内容既可以是指令也可以是数据,数据可分为"用于运算的数值"和"表示内存地址的数值"两种;
决定程序流程的程序计数器
CPU每执行一个指令,程序计数器的值就会增加1;
条件分支和循环机制
程序的流程分为顺序执行、条件分支和循环三种;
顺序执行是指按照地址内容的顺序执行指令,条件分支是指根据条件执行任意地址的指令,循环是指重复执行同一地址的指令;
以条件分支为例:
溢出(overflow):指运算的结果超出了寄存器的长度范围;
函数的调用机制
函数调用使用的是call指令,而不是跳转指令,call指令会把调用函数后要执行的指令地址存储在名为栈的主存内,return命令的功能是把保存在栈中的地址设定到程序计数器中;
是否执行跳转命令,则由CPU在参考标志寄存器的数值后进行判断
通过地址和索引实现数组
数组是指同样长度的数据在内存中进行连续排列的数据构造,用一个数组名来表示全体数据,通过索引来区分数组的各个元素(数据);
想要像数组那样分割特定内存区以达到连续查看的目的,使用两个寄存器方便些(基址寄存器和变址寄存器);
CPU的处理其实很简单
机器语言指令的主要类型与功能:
CPU执行的指令就四种:存取数据、运算数据、逻辑跳转、函数的调用和回退;
二、数据是二进制数表示的
用二进制数表示计算机信息的原因
计算机内部是由IC这种电子部件构成的,CPU和内存也是IC的一种,IC有很多引脚(位),只有直流电压为0V或5V两个状态,IC的一个引脚只能表示两个状态,决定了计算机的数据只能用二进制数处理;
二进制数的位数一般是8位、16位、32位......也就是8的二进制数,8位二进制数称为一个字节,位是最小单位,字节是基本单位;
广义上说,一样的数据(一堆二进制文件),根据不同的角度去看待它就会不一样,可以是数值或字符也可以是别的,但实际上如果这段数据在代码中,就是指令,如果在数据段中,就是数据;
什么是二进制数
二进制以2为基数的计数方法,十进制以10为基数;
移位运算和乘除运算的关系
移位计算指的是将二进制数值的各数位进行左右移位(shift)的运算;
a = 39;
b = a << 2;
左移动两位转换成十进制是156,正好是39的四倍;
十进制数左移后变成原来的10倍、100倍、1000倍,二进制数左移后就会变成原来的2倍、4倍、8倍...
便于计算机处理的''补数''
二进制数中表示负数值时,一般就会把最高位作为符号来使用,所以把最高位称为符号位;
符号位是0时表示正数,是1时表示负数;
计算机做减法时实际上是在做加法,在表示负数时需使用''补数'',就是用正数来表示负数;
补数即将二进制数的各数位数值全部取反(二进制数各数位的0变成1,1变成0);
负数表示有误的情况:
补数求解的变换方法就是''取反+1''
编程语言包含的整数数据类型中,有的可以处理负数,有的不能:C语言中short类型是将最高位为1的数值看作补数,而unsigned short 类型则是32768以上的值;// ps:-32768~32767这样负数比正数多一个的原因是最高位时0的正数有0~32767共32768个,最高位是1的负数有-1~-32768共32768个;
逻辑右移和算术右移的区别
右移有移位后再最高位补0和补1两种情况:
逻辑右移:二进制数表示图形模式而非数值时,移位后需要在最高位补0;
算术右移:二进制数作为带符号的数值进行运算时,移位后在最高位填充移位前符号位的值(0或1),数值是用补数表示的负数值,右移后在空出来的最高位补1,可以实现1/2,1/4,1/8等的数值运算,如果是正数,只需在最高位补0即可;
符号扩充:指在保持值不变的前提下将8位转换成16位和32位的二进制数;
掌握逻辑运算的窍门
算术运算是指加减乘除四则运算,逻辑运算是指二进制数各数字位的0和1分别处理的运算,包括逻辑非、逻辑与、逻辑或和逻辑异或四种;
逻辑运算要摒弃二进制数表示数值的观点,应该看成图形或者开关上的ON/OFF(1/0);
对图形模式进行4种逻辑运算的结果(白色表示1,黑色表示0)
三、计算机进行小数运算时出错的原因
将0.1累加100次也得不到10
二进制数的小数点后第一位的位权是2^-1=0.5,即二进制数0.1用十进制数表示为1*0.5=0.5,十进制数0.625转换成二进制数是0.101;
浮点数是指把小数用"符号 尾款*基数的指数幂"这种形式来表示;
二进制数的基数是2,十进制数的基数是10;
用二进制数表示小数
二进制数小数点前面部分的位权,第一位是2的0次幂、第二位是2的1次幂...小数点后面部分的位权第一位是2的-1次幂...
计算机运算出错的原因
计算机计算出错的原因是因为"有一些十进制数的小数无法转换成二进制数";
十进制数0的下一位是0.0625,因此这中间的小数无法用小数点后4位数的二进制数来表示;0.0625的下一位一下子变成了0.125,所以0.1这个小数转换二进制数会变成无限循环小数,那么计算机就会根据变量类型所对应的长度将根据数据类型长度截断或者四舍五入;
什么是浮点数
浮点数是指用符号、尾数、基数和指数这四部分来表示的小数;
符号部分是指使用一个数据位来表示数值的符号,该数据位是1时表示负,为0时表示"正或0";
尾数部分用的是"将小数点前面的值固定为1的正则表达式";
指数部分用的是"EXCESS系统表现";
正则表达式和EXCESS系统
按照特定的规则来表示数据的形式即正则表达式,除小数之外,字符串以及数据库等,也有各自的正则表达式;
EXCESS系统表现是指通过将指数部分表示范围的中间值设为0,使得负数不需要用符号来表示;
在实际的程序中进行确认
//用于确认单精度浮点数表示方法
#include <stdio.h>
#include <string.h>
int main()
{
float data;
unsigned long buff;
char s[34];
data = (float)0.75;
memcpy(&buff,&data,4);
for (int i = 33;i >= 0;i--)
{
if (i == 1|| i == 10) s[i]='-';
else if (buff %2 == 1) s[i] = '1';
else s[i] = '0';
buff /= 2;
}
s[34] = '\0';
printf ("%s\n",s);
}
D:\xr\cmake-build-debug\xr.exe
0-00111111-10000000000000000000000(符号-指数-尾数)
正数-126(用EXCESS系统表现为126-127=-1)-尾数1.5
Process finished with exit code 0
如何避免计算机计算出错
回避策略(无视这些错误)和把小数转换成整数来计算;
二进制数和十六进制数
在C语言中只需在数值的开头加上0x就可以表示十六进制数;二进制数的4位相当于十六进制数的1位;
四、熟练使用有棱有角的内存
内存的物理机制很简单
有十个地址信号引脚的内存IC可以指定的地址范围用二进制数表示的话是0000000000~1111111111(用二进制数表示的话是0~1023);
高级编程语言中的数据类型表示的是占据内存区域的大小和存储在该内存区域的数据类型;
在32位内存地址的环境中,指针变量的长度是32位,指针指的是用于存储内存地址的变量;
与物理内存有着相同构造的数组的数据类型长度是1字节;
用LIFO方式进行数据读写的数据结构称为栈,栈是一种后入先出的数据结构;
根据数据的大小链表分叉成两个方向的数据结构称为二叉查找树,二叉查找树指的是从节点分成两个叉的树状数据结构;
内存IC中有电源、地址信号、数据信号、控制信号等用于输入输出的大量引脚,通过为其指定地址来进行数据的读写,大多数+5v的直流电压表示1,0v表示0;
可以将内存比作酒店,电源就是是否营业,地址信号就是房间号,数据信号就是房间内的东西,控制信号就是是否取出房间里的东西;
内存的逻辑模型是楼房
简单的指针
指针是一种变量,表示的不是数据的值而是存储着数据内存地址。
在定义指针时,我们通常会在变量名前加一个星号*;
数组是高效使用内存的基础
数组是指多个同样数据类型的数据在内存中连续排列的形式;
作为数组元素的各个数据会通过连续的编号被区分开来,这个编号称为索引;指定索引后,就可以对该索引所对应地址的内存进行读写操作;(CPU是通过利用基址寄存器和变址寄存器来指定内存地址的)
数组是使用内存的基本,是因为数组与内存的物理构造完全一致;
栈、队列以及环形缓冲区
栈用的是LIFO方式,而队列用的是FIFO方式;
Push:往栈中写入数据的函数;Pop:从栈中读出数据的函数;
EnQueue:往队列中写入数据的韩束;DeQueue:往队列中写入数据的函数;
链表使元素的追加和删除更容易
链表和二叉查找树都是不用考虑索引的顺序就可以对数组元素进行读写的方式;通过使用链表可以更高效地对数组数据(元素)进行追加和删除处理,通过使用二叉查找树可以更加高效地对数组进行检索;
高效的原因是因为不需要直接删除物理内存中的数据,而只通过修改索引的地址;
链表的示例:
删除链表的第三个元素的方法:
链表中追加元素的方法:
单纯使用数组的情况下的元素删除:
单纯使用数组的情况下的元素追加:
二叉查找树使数据搜索更有效
二叉树查找是指在链表的基础上往数组中追加元素时,考虑到数据的大小关系,将其分成两个方向的表现形式;
二叉树查找需要数据的值和两个索引信息,一个左边索引,一个右边索引;
五、内存和磁盘的关系
通过使用内存来提高磁盘访问速度的机制称为磁盘缓存,指的是把磁盘中读出的数据存储在内存中,当该数据再次被读取时,不是从磁盘而是直接从内存中高速读出;
把磁盘的一部分作为假想内存来使用的机制称为虚拟内存,借助虚拟内存,哪怕内存容量不足的计算机,也可以运行很大的程序;
Windows中,在程序运行时,存储着可以动态加载调用的函数和数据文件称为DDL;
在EXE程序文件中,静态加载函数的方式称为静态链接;
扇区是磁盘保存数据的物理单元,一般磁盘的1个扇区是512字节;
不读入内存就无法运行
程序保存在存储设备中,通过有序地被读出来实现运行,这一机制称为存储程序方式;
磁盘缓存加快了磁盘访问速度
磁盘缓存指的是磁盘中读出来的数据存储到内存空间中的方式;
虚拟内存把磁盘作为部分内存来使用
虚拟内存是指把磁盘的一部分作为假想的内存来使用;
虚拟内存的方法有分页式和分段式两种;分段式把运行的程序分割成处理集合及数据集合等为单位的段落,然后再以分割后的段落为单位在内存和磁盘之间进行数据置换;分页式是指在不考虑程序构造的情况下把运行程序按照一定大小的页进行分割,并以页为单位在内存和磁盘间进行置换;
节约内存的编程方法
图形用户界面:像Windows这样,窗口的菜单及图表等都可以进行可视化操作的方式;
把应用文件变小的方法:
通过DLL文件实现函数共有;
DLL文件是在程序运行时可以动态加载Library(函数和数据的集合)的文件;
通过调用_stdcall来减小程序文件的大小
C语言中在调用函数后需要执行栈清理处理指令,栈清理处理是指把不需要的数据从接受和传递函数的参数时使用的内存上的栈区域中清理出去;
在C语言中,函数的返回值是通过寄存器而非栈来返回的;
磁盘的物理结构
磁盘的数据保存是以簇为单位进行;
六、亲自尝试压缩数据
文件是字节数据的集合体,文件储存的基本单位是1字节(=8位);
文件内容用"数据的值×循环次数"来表示的压缩方法是RLE算法;
BMP格式的图像文件是没有被压缩的,因此要比JPEG格式等压缩过的图像文件大不少;
文件以字节为单位保存
文件是字节数据的集合体
RLE算法的机制
通过数据的重复次数来实现压缩的RLE算法;
RLE算法的缺点
针对相同数据经常连续出现的图像,文件等,RLE算法可以发挥不错的效果,但它并不适合文本文件的压缩
通过摩尔斯编码来看哈夫曼算法的基础
压缩软件LHA,使用的就是哈夫曼算法;
莫尔斯编码不是通过语言,而是通过"嗒嘀嗒嘀"这些长点和短点的组合来传递文本信息的;
用二叉树实现哈夫曼算法的基础
哈夫曼算法是指为各压缩对象文件分别构造最佳的编码体系,并以该编码体系为基础来进行压缩;
在哈夫曼算法中,通过借助哈夫曼树构造编码体系,即使在不使用字符区分符号的情况下,也可以构建能够明确进行区分的编码体系;
第一步:统计压缩文件中的词频;
第二步:根据词频设计该文件最佳的编码体系;
第三部:根据生成的编码体系压缩文件;
哈夫曼算法能够大幅提升压缩比率
使用哈夫曼树后,出现频率越高的数据所占用的数据位数就越少,而且数据区分也可以很清晰地实现;
图像文件是离散化存储,实际上图像文件就是一堆像素点构成的,使用RGB(红绿蓝三原色)和灰度值(反应明亮程度),每个色彩通道使用一个字节存储,一个像素点需要四个字节,一张图的大小随着像素点的多少变化;
可逆压缩和非可逆压缩
把能还原到压缩前状态的压缩称为可逆压缩,无法还原到压缩前状态的压缩称为非可逆压缩;
七、程序是在何种环境中运行的
应用的运行环境指的是操作系统和计算机本身(硬件)的种类,通常是用类似于Windows(OS)和AT兼容机这样的OS和硬件的种类来表示;
FreeBSD是一种Unix操作系统,通过在各个环境中编译Ports中公开的代码,就可以执行由此生成的本地代码了;
模拟器是指在Macintosh上提供虚拟的Windows环境;
Java虚拟机的功能是运行Java应用的字节代码,只要为各个环境安装专用的Java虚拟机,同样的字节代码就能在各种环境中下运行了;
运行环境=操作系统+硬件
CPU只能解释其自身固有的机器语言,机器语言的程序称为本地代码,程序员编写的程序在编写阶段仅仅是文本文件,文本文件(排除文字编码的问题),在任何环境下都能显示和编辑,我们称之为源代码,通过对源代码编译,可得到本地代码;
Windows克服了CPU以外的硬件差异
在Windows的应用软件中,键盘输入、显示器输出等并不是直接向硬盘发送指令,而是通过向Windows发送指令来间接实现的;
不同操作系统的API不同
应用程序向操作系统传递指令的途径称为API;
操作系统提供了操作如显示器、键盘等硬件的API,应用程序在操作系统的管理下执行,因此应用程序只能调用操作系统提供的API来操作硬件;
应用程序由CPU运行,而CPU有支持的指令集,因此应用程序在编译时需要编译成该CPU所支持的指令,才能在这个CPU上运行;
FreeBSD Port帮你轻松使用源代码
Unix系列操作系统FreeBSD中,存在一种名为Ports的机制,该机制能够结合当前运行的硬件环境来编译应用的源代码,进而得到可以运行的本地代码系统,如果目标应用的源代码没有在硬件上的话,Ports就会自动使用FTP连接到相关站点来下载代码;
FreeBSD提供一种基于源代码和不同硬件CPU实现的灵活编译,从而让操作系统自身拥有适应不同CPU硬件的能力;
利用虚拟机获得其他操作系统环境
虚拟机技术:实现在一种操作系统下运行另一种操作系统应用的技术;
没有虚拟机时,应用程序需要先找到操作系统找对应资源,找到后这些资源如dll库就在cpu运行;
有了虚拟机后,应用程序先到虚拟机操作系统找资源,然后虚拟机操作系统的资源再通过虚拟机层的翻译再到实际操作系统找资源,然后再到CPU运行;
逻辑上看,是分层次的,实际上在内存中就是对应不同的地址段,CPU在不同的地址段上跳转取指令并执行;
提供相同运行环境的JAVA虚拟机
JAVA有两个层面的意思:一个是作为编程语言的JAVA,另一个是作为程序运行环境的JAVA;
JAVA编译生成的并不是特定CPU使用的本地代码而是名为字节代码的程序,字节代码运行环境称为Java虚拟机(JVM),Java虚拟机是一边把Java字节代码逐一转换成本地代码一边运行的;
BIOS和引导
BIOS存储在ROM中,是预先内置在计算机主机内部的程序,BIOS除了键盘、磁盘、显卡等基本控制程序外,还有启动"引导程序"的功能,引导程序是存储在启动驱动器起始区域的小程序;
在ROM中预制了BIOS,通电启动后,BIOS检查硬件是否正常,然后启动引导程序,通过引导程序启动操作系统;
八、从源文件到可执行文件
CPU可以解析和运行的程序形式为本地代码(机器语言代码);
将多个目标文件结合生成EXE文件的工具是链接器;
扩展名为.obj的目标文件的内容是本地代码;
把多个目标文件收录在一起的文件称为库文件;
仅包含Windows的DLL文件中存储的函数信息的文件称为导入库;
在程序运行时,用来动态申请分配的数据和对象的内存区域形式称为堆;
计算机只能运行本地代码
用某种编程语言编写的程序就称为源代码,保存源代码的文件称为源文件;
转换成机器语言的程序就是本地代码;
编译器的作用就是把源代码编程与具体操作系统能进行资源对接的,同时CPU能够识别执行的机器语言;
本地代码的内容
Windows中exe文件的程序内容,使用的就是本地代码;
Dump是指把文件的内容,每个字节用2位十六进制来表示的方式;
机器语言的本质是数值序列,数值含义要么是指令,要么是数据;
编译器负责转换源代码
能够把C语言等高级编程语言编写的源代码转换成本地代码的程序称为编译器;
静态编译性语言(如C,C++,Java)需要编译器,动态解释性语言(如JavaScript,python)没有编译器,而是解释器;
仅靠编译是无法得到可执行文件的
编译器转换成源代码后,就会生成本地文件(目标文件.obj),但本地文件是无法直接运行的,为了得到可运行的exe文件,编译之还需进行"链接"处理;
把多个目标文件结合,生成1个exe文件处理就是链接,运行连接的程序就是链接器;
运行机制:编译(生成.obj文件)、链接(生成可执行文件)、运行;
启动及库文件
目标文件记述的是同所有程序起始位置相结合的处理内容,称为程序的启动;
库文件指的是把多个目标文件集成保存到一个文件中的形式;链接器指定库文件后,就会从中把需要的目标文件抽取出来,并同其他目标文件结合生成exe文件;
外部符号是指其他目标文件中的变量或函数;
标准函数不是通过源代码形式而是通过库文件形式和编译器一起提供的;
DLL文件及导入库
Windows以函数的形式为应用提供了各种功能,这些形式的函数称为API(应用程序接口);
Windows中,API的目标文件并不是存储在通常的库文件中,而是存储在名为DLL文件的特殊库文件中;(程序运行时动态结合的文件)
存储着目标文件的实体,并直接和EXE文件结合的库文件形式称为静态链接库;
静态链接库(.lib):含目标文件实体,直接与.exe文件结合;
动态链接库(.dll):程序执行时调用,如API的目标文件;
导入库(.lib):存储调用信息,无实体内容;
可执行文件运行时的必要条件
EXE文件是作为单独得文件储存在硬盘中的,通过资源管理器找到并双击EXE文件,就会把EXE文件的内容加载到内存中运行;本地代码在对程序中记述的变量进行读写时,是参照数据存储的内存地址来运行命令的
exe文件中给变量及函数分配了虚拟的内存地址,在程序运行时虚拟的内存地址会转换成实际的内存地址,链接器会在exe文件的开头,追加转换内存地址所需的必要信息,这个信息称为再配置信息;
exe文件里并没有变量或者函数在内存中的实际地址,而是通过一个虚拟地址来描述,也就是变量组的基址,函数组的基址,各变量和函数通过对基址的偏移量进行寻址,当程序加载到内存中时,变量基址和函数基址是动态分配的,然后通过对基址的偏移量就可以找到变量或函数的地址,exe文件记录了变量或函数所需的内存空间的大小,否则在实际给变量和函数分配内存空间时不知道需要申请多少的内存空间大小;
程序加载时会生成栈和堆
EXE文件的内容分为再配置信息,变量组和函数组;当程序加载到内存后,除此之外还会额外生成栈和堆,栈是用来存储函数内部临时使用的局部变量以及函数调用时所用的参数的内存区域;堆是用来存储程序运行时的任意数据及对象的内存领域;
内存中的程序就是用于变量的内存空间、用于栈的内存空间、用于堆的内存空间这四部分构成;
使用栈的数据的内存空间,每当函数被调用时都会得到申请分配,并在函数处理完毕后自动释放,而堆的内存空间则要根据程序员编写的程序来明确进行申请分配或释放;
内存泄露:如果没有在程序中明确释放堆的内存空间,即使在处理完毕后该内存空间仍会一直残留;
使用堆的内存空间:C通过malloc()函数来进行申请分配、通过free()函数来释放;
C++通过new运算符来申请分配通过,通过delete运算符来释放;
有点难度的Q&A
编译器是在运行前对所有源代码进行解释处理的,而解释器则是在运行时对源代码的内容一行一行进行解释处理的;
DLL文件中的函数可以被多个程序共用,借助该功能可以节约内存和磁盘,对函数内容进行修正时,还不需要重新链接(静态链接)使用这个函数的程序;
垃圾回收机制指的是对处理完毕后不再需要的堆内存空间的数据和对象(堆中的object不是目标文件,而是面向对象编程语言的object(对象,数据和处理的集合体))进行清理,释放它们所使用的内存空间
九、操作系统和应用的关系
监控程序可以说是操作系统的原型,主要功能是程序的加载和运行;
调用操作系统功能称为系统调用,应用通过系统调用间接控制硬件;
GUI是图形用户界面;
操作系统功能的历史
操作系统也成称为基础软件,操作系统是计算及运行时不可或缺的控制程序,以及在控制程序下运转的为其它软件运行提供操作环境的软件的统称;
操作系统是多个程序的集合体;
基础软件是操作系统、数据库系统、中间件、语言处理系统(包括编译程序、解释程序、汇编程序)和办公软件的统称;
要意识到操作系统的存在
在操作系统这个运行环境下,应用并不是直接控制硬件,而是通过操作系统来间接控制硬件的;
操作系统收到应用发出的指令后,首先会对该指令进行解释,然后会对时钟IC(实时时钟)和显示器用的I/O进行控制;
系统调用和高级编程语言的移植性
操作系统的硬件控制功能,通常是通过一些小的函数集合体的形式来提供的,这些函数及调用函数的行为统称为系统调用(应用对系统的功能进行调用);
真正的系统调用代码被库函数封装起来了,通常不直接面向程序员,程序员看到的通常只是函数;
操作系统和高级编程语言使硬件抽象化
硬件抽象层(HAL)
操作系统和高级编程语言能够使硬件抽象化;
Windows操作系统的特征
32(64)位操作系统
通过API函数集来提供系统调用
Windows是通过名为API的函数集来提供系统调用的,API是联系应用程序和操作系统之间的接口;
API通过多个DLL文件来提供;
提供采用了GUI的用户界面
GUI指的是通过点击显示器中的显示的窗口等即可进行可视化操作的用户界面
通过WYSIWYG实现打印输出
最初为了实现在显示器中显示和打印机中打印,就必须分别编写各自的程序,而在Windows中,借助WYSIWYG功能就可以实现这两个操作;
提供多任务功能
多功能任务指的是同时运行多个程序的功能,Windows是指通过时钟分割技术来实现多任务功能的;
时钟分割指的是在短时间间隔内,多个程序切换运行的方式;
Windows还具有以程序中的函数为单位来进行时钟分割的多线程功能;
提供网络功能及数据库管理
网络功能和数据库功能是处于操作系统和应用的中间,被统称为中间件,操作系统和中间件合在一起称为系统软件;
应用可以利用操作系统和中间件的功能;
通过即插即用实现设备驱动的自动设定
即插即用指的是新的设备连接后立刻就可以使用的机制;
程序是操作系统、中间件、应用等所有软件的统称;应用必然会通过某种形式利用操作系统的功能;
十、通过汇编语言了解程序的实际构成
本地代码的指令中,表示其概念的英文缩写是助记符;
汇编代码的源代码使用汇编器转换成本地代码的方式称为汇编;
本地代码转换成汇编语言的源代码的方式称为反汇编;
汇编语言的源文件的扩展名通常格式是.asm;
汇编语言程序中的段定义指的是构成程序的命令和数据的集合组;
通过汇编语言的跳转指令,可以实现循环和条件分支;
汇编语言和本地代码是一一对应的
在加法运算的本地代码加上add,在比较运算的本地代码加上cmp,这些英文缩写叫做助记符,使用这些助记符的语言称为汇编语言;
反汇编很容易,因为汇编语言和机器语言一一对应;反编译有难度,因为高级语言和源代码不是一一对应的;
通过编译器输出汇编语言的源代码
C语言的源代码和转换成汇编语言的源代码是交叉显示的0。
(;)以后是注释
不会转换成本地代码的伪指令
汇编语言的源代码是由本地代码的指令(操作码)和针对汇编器的伪指令构成的;
伪指令负责把程序的构造及汇编的方法指示给汇编器(转换程序);
由伪指令segment和ends围起来的部分是给构成程序的命令和数据的集合体加上一个名字而得到的,称为段定义;
_TEXT是指令的段定义,_DATA是被初始化(有初始值)的数据的段定义,_BSS是尚未初始化的数据的段定义;
汇编语言的语法是"操作码+操作数"
操作码表示的是指令动作,操作数表示的是指令对象;(类似于mov这样的指令称为操作码,作为指令对象的内存地址及寄存器称为操作数)
CPU和内存的关系
寄存器是CPU中的存储区域,不过寄存器不仅仅具有存储指令和数据的功能,也有运算的功能;
x86系列CPU的主要寄存器:
最常用的mov指令
指令中最常使用的是对寄存器和内存进行数据存储的mov指令;
mov指令的两个操作数分别用来指定数据的存储地和读出源。操作数可以指定寄存器、常数、标签以及用方括号围起来的内容,方括号中的值则会被解释为内存地址,然后就会对该内存地址对应的值进行读写操作;
对栈进行push和pop
程序运行时会在内存上申请一个称为栈的数据空间;栈是存储临时数据的区域,特点是通过push指令和pop指令进行数据存储和读出;
栈的模型:
对栈进行读写的内存地址是由esp寄存器(栈指针)进行管理的
函数的调用机制
函数调用时栈发挥大作用的场合;
函数调用的汇编语言代码:
在汇编语言中,函数名表示的是函数所在的内存地址;
push和pop指令必须以4字节为单位对数据进行入栈和出栈处理;
函数调用前后栈的状态变化:
函数内部的处理
函数内部的处理:
ebp寄存器的值在(1)中入栈,在(5)出栈;
函数的参数是通过栈来传递,返回值是通过寄存器来返回的;
栈的最高位的数据地址一直存储在esp寄存器中的;
始终确保全局变量用的内存空间
C语言中,在函数外部定义的变量称为全局变量,在函数内部定义的变量称为局部变量,全局变量可以引用源代码的任意部分,局部变量只能在定义该变量的函数内进行引用;
临时确保局部变量用的内存空间
局部变量是临时保存在寄存器和栈中的,所以局部变量只能在定义该变量的函数内进行引用;
寄存器空闲时就使用寄存器,寄存器空间不足时就使用栈;寄存器速度更快,从理论上说减少参数个数或局部变量数量都能优化性能;
循环处理的实现方法
执行循环处理的C语言源代码:
定义MySub函数
void MySub()
{
//不做任何处理
}
// 定义MyFunc函数
Void MyFunc()
{
int i;
for (i =0; i < 10; i++ )
{
//重复调用MySub函数10次
MySub();
}
}
for语句转换成汇编语言的结果:
xor ebx, ebx ; 将ebx寄存器清0
@4 call _MySub ; //调用MySub函数
inc ebx ; //ebx寄存器的值加1
cmp ebx,10 ; //将ebx寄存器的值和10进行比较
jl short @4 ; //如果小于10 就跳转到@4
C语言的for语句是通过在括号中指定循环计数器的初始值(i=0),循环的继续条件(i<10),循环计数器的更新(i++)这三种形式来进行循环处理的;
而汇编语言的源代码中,循环是通过比较指令(cmp)和跳转指令(jl)来实现的;
条件分支的实现方法
进行条件分支的C语言源代码:
定义MySub1函数
void MySub1()
{
//不做任何处理
}
//定义MySub2函数
void MySub2()
{
//不做任何处理
}
//定义MySub3函数
void MySub3()
{
//不做任何处理
}
//定义MyFunc函数
void MyFunc()
{
int a =123;
//根据条件调用不同的函数
if (a > 100)
{
MySub1();
}
else if (a < 50)
{
MySub2();
}
else
{
MySub3();
}
}
转换成汇编语言后的结果:
_MyFunc proc near
push ebp;
mov ebp, esp;
mov eax,123 ;把123存入eax寄存器中
cmp eax,100 ;把eax寄存器的值同100进行比较
jle short @8 ;等于或小于100时,跳转到@8标签
call _MySub1 ;调用MySub1函数
jmp short @11 ;跳转到@11标签
@8: cmp eax,50 ;把eax寄存器的值同50进行比较
jge short @10 ;大于等于50时,跳转到@10标签
call _MySub2 ;调用MySub2函数
jmp short @11 ;跳转到@11标签
@10: call _MySub3 ;调用MySub3函数
@11: pop ebp
ret
_MyFunc endp
了解程序运行方式的必要性
"线程"是操作系统分配给CPU的最小运行单元,源代码的一个函数就相当于一个线程,多线程处理指的是在一个程序中同时运行多个函数的意思;
十一、硬件控制方法
在汇编语言中,用IN指令和OUT指令来同外围设备进行输入输出操作;
I/O是Input和Output的缩写;
I/O地址或I/O端口号用来识别外围设备的编号;
IRQ是Interrupt Request的缩写,用来执行硬件中断请求的编号;
DMA是Direct Memory Access的缩写,指的是不经过CPU中介处理,外围设备直接同计算机主内存进行数据传输;
DMA通道用来识别具有DMA功能的外围设备的编号;
应用和硬件无关?
利用操作系统提供的系统调用功能就可以实现对硬件的控制,在Windows中,系统调用称为API,各API就是应用调用的函数,这些函数的实体被存储在DLL文件中;
在向窗口和打印机输出字符串时,可以使用Windows提供的TextOut函数作为API,而C语言中的printf函数是用来命令提示符中显示字符串的函数,使用printf函数,是无法向窗口和打印机输出字符串的;
支撑硬件输入输出的IN指令和OUT指令
I/O控制器中有用于临时保存输入输出数据的内存,这个内存就是端口;I/O控制器内部的内存也称为寄存器,但和CPU内部寄存器在功能上是不同的,CPU内部寄存器用来处理数据运算的,而I/O寄存器用来临时存储数据的;
端口号也成为了I/O地址,IN指令和OUT指令在端口号指定的端口和CPU之间进行数据的输入输出;
编写测试用的输入输出程序
操作系统控制硬件的方式同CPU控制内存是一样的,通过CPU和相关硬件进行数据交互传递,控制数电和模电信号,实现硬件功能;
外围设备的中断请求
IRQ是用来暂停当前正在运行的程序,并跳转到其他程序运行的必要机制,该机制称为中断处理;
实施中断请求的是连接外围设备的I/O控制器,负责实施中断处理程序的是CPU;
中断控制器的功能:
中断请求的顺序:
用中断来实现实时处理
按照顺序调查多个外围设备的状态称为轮询,中断触发是外围设备主动打断主程序,轮询是被动等待;
DMA可以实现短时间内传送大量数据
DMA是指在不通过CPU的情况下外围设备直接和主内存进行数据传送;
依靠CPU控制I/O进行数据传送的方式叫编程式I/O,两者并不互斥,编程式I/O可以与DMA结合使用。实际上,DMA的启动就是由CPU通过编程式I/O发送的启动命令,随后脱离CPU控制进行DMA数据传送,DMA完成后发送中断告知CPU;
文字及图片的显示机制
显示器中显示的信息一直存储在某内存中,该内存称为VRAM;
在程序中,只要往VRAM中写入数据,该数据就会在显示器中显示出来,实现该功能的程序是由操作系统或BIOS提供,并借助中断来进行处理的;
VRAM中写入的数据被显示在显示器上:
十二、让计算机“思考”
计算机模拟是指用软件来进行实际实验;
伪随机数同真正的随机数不同,具有周期性;
随机数的种子不同,产生的随机数也是不同的;
作为"工具"的程序和为了"思考"的程序
程序的使用目的分为两类:作为工具使用和用程序代替人类的思考过程;
用程序来表示人类的思考方式
通常所说的随机数指的是统一随机数,统一随机数指的是在一定数值范围内各数出现频率相同的随机数形式,C语言中的rand()函数的返回值就是统一随机数;
用程序来表示人类的思考习惯
习惯是人类的思考方式,如果要用程序来表示人类的·习惯,就需要对习惯进行定量表现;
程序生成随机数的方法
计算机的生成随机数通常是借助公式产生的,不是真正意义上的随机,理论上如果给予公式一致的参数,那么随机数都是可推断的,是伪随机的;
活用记忆功能以达到更接近人类的判断
计算机不具备思考功能,但有记忆功能,可以根据记忆给出合理的下一步,以实现近乎智能;
用程序来表示人类的思考方式
计算机本身不智能,它只是运行了表现人类的思考方式的程序;
830

被折叠的 条评论
为什么被折叠?



