操作系统真相还原第0章笔记

什么是陷入内核
应用程序处于特权级别3,操作系统内核处于特权级0,当用户程序访问系统资源时,(无论是硬件,还是内核数据结构),
它都需要进行系统调用,这样CPU便进入了内核态,也称为管态。
内存访问为什么要分段
编译器在编译程序时,肯定要根据CPU访问内存的规则将代码编译成机器指令,这样编译出来的程序才能在该CPU上运行,
所以说,在直接以绝对物理地址访问内存的CPU上运行程序,该程序中指令地址也必须是绝对的物理地址。
总之要想在该硬件上运行,就要遵从该硬件的规则。
若加载程序运行,不管其是内核程序,还是用户程序,程序中的地址若都是绝对的物理地址,那该程序必须在内存中的固定
地方,于是,两个编译的程序地址相同没有办法做到同时运行,只能运行一个,于是让CPU采用了“段基址+段内偏移地址”
的方式来访问任意程序了,这样的好处是程序可以重定位,尽管程序指令中给的是绝对的物理地址,但终究可以同时运行多个
程序了。
总结:编译器是根据CPU特性进行的指令机器码生成,如果使用的都是绝对的物理地址那么就没有办法同时运行两个编译的程序,
因此给出了“段基址+段内偏移”的方式实现了程序重定位进而为同时运行多个程序做好准备。
段基址+段内偏移地址
CPU设计者在地址处理单元中动了手脚,自动将段基址乘以16及左移4位,然后在和16位的段内偏移相加,这下地址就变成了20位。
代码中为什么存在代码段,数据段?
在X86平台的处理器中必须用到分段访问内存,正因如此处理器才提供了段寄存器,用来指定待访问内存段起始地址,
在硬件的内存访问机制中,处理器要用硬件-段寄存器指向软件中的内存段。
平坦模式:硬件段寄存器中指向的内存段最大为4GB。
多段模式:硬件段寄存器中指向内存段大小不一,像是汇编语言允许程序员自己分段,能够灵活安排布局,属于人为分段,
也就是采用了多段模型编程。
分页模型:由于处理器支持具有分页机制的虚拟内存,操作系统也采用分页模型因此编译器将程序的内容分为代码段,
数据段,比如gcc编译C语言程序就划分了代码段,数据段,栈段,.bss段,堆等内容,操作系统会将编译器编译的
用户程序段的内容分配到不同的物理地址上。
段的不同属性
数据段本身是需要被修改的,所以数据段就需要要可写属性,程序中的代码是不能被更改的,这样就要去代码段具备只读属性。
实现段不同的属性:
1.编译器负责挑选出数据具备的属性,从而根据属性将程序分段(代码段/数据段)分类,比如划分出只读属性的代码段和写属性的数据段,
编译器并没有让段具备某种属性而是归类到一起而已,也就是将程序多个section合并成一个大的segment。
2.操作系统通过设置GDT全局描述符表来构造段描述符,在段描述符中指定段的位置,大小及属性(包括S字段和TYPE字段),也就是说
操作系统认为代码段是只读的,所以给用来指向代码段的那个段描述符设置了只读属性,这才是真正的段添加属性的地方。
3.CPU中的段寄存器提前被操作系统赋予相应的的选择子,从而确定了指向的段,在执行指令时,会根据该段的属性来判断指令的行为,
若有返回则发出异常。
总结:编译器/操作系统/CPU这个三个的配合在一起才能对程序保护。
物理地址,逻辑地址,有效地址,线性地址,虚拟地址的区别
物理地址:在实模式下段基址+段偏移地址经过段部件的处理,直接输出的就是物理地址,CPU可以直接访问。	
线性地址:在保护模式下段基址+段偏移称为线性地址,不过段基址并不是真正的地址了,而是被称为段选择子,本质上是一个
索引,类似于数组下标,这个索引能在GDT(全局描述符表)中找到相应的段描述符,该描述符记录了段的起始地址,大小等信息,
这样便获得了段基址,没有开启分页功能,线性地址就是物理地址可以直接访问内存。
虚拟地址:虚拟地址是保护模型下的一种模式,是在开启分页功能后将线性地址转变为虚拟地址而非是物理地址,虚拟地址需要经过CPU的
页部件转换成具体物理地址。
有效地址:无论是保护模式还是实模式,段内偏移地址又被称为有效地址,也被称为逻辑地址。
段重叠
段重叠是指两个段基址+偏移后得到的地址范围相重合,比如C00+05和C02+2,C00和C02就重叠。
平坦模型
平台模式是相对于多端模式而言的,在实模式下访问超过64KB的内存需要重新指定不同的段,需要迂回的方式才能达成目标,
在保护模式下其是32位的,寻址能够达到4GB,段内偏移地址也是地址,所以32位环境下一个段就能够访问所有内存了,所以称为
平坦模式,相较于多段模式需要A20地址线延申访问1MB空间,平坦模式则不需要。
cs,ds这类sreg寄存器,位宽是多少
CS	代码段寄存器(Code Segment Register),其值是代码段的段基址。
DS	数据段寄存器(Data Segment Register),其是数据段的段基址。
ES	附加段寄存器(Extra Segment Register),其值是附加段的段基址,称为附加是因为此段寄存器用途不想其他sreg固定。
FS	附加段寄存器(Extra Segment Register),其值是附加段的段基址,用途不固定。
GS	附加段寄存器(Extra Segment Register),其值为附加数据段的段基址,用途不固定。
SS	堆栈段寄存器(Stack Segment Register),其值为堆栈的段值。
每种模式下段寄存器的意义不同:
实模式:CS/DS/ES/SS的值为段基址,是具体的物理地址,内存单元的逻辑仍然是段基址+段内偏移
保护模式:段寄存器不在是段地址,而是段选择子(Selector),选择子也是数值,长度仍然是16位。
结论:32位的CPU,sreg无论是工作在16位的实模式中,还是32位保护模式中用的段寄存器都是同一组,
32位下的段选择子是16位宽度,排除了寄存器32位环境下是32位宽的可能,sreg都是16位宽。
编译器程序和解析型程序的区别
解析型语言:JavaScript/Python/Perl/PHP/等,它们本身是文本文件,是某个应用程序的输入这个应用程序就是脚本解析器,
脚本中的代码没有真正上过CPU去执行,cs:ip从来没指向过它们,CPU眼里只有脚本解析器,本质上脚本解析器实时分析脚本运行。
编写型语言:运行时本身就是一个进程,由操作系统直接调用将CS:IP直接指向这个程序入口,使它在CPU上运行。
大端字节序/小端字节序
内存是以字节为单位进行读写的,其最小的读写单位就是字节。
小端字节序:
	数值的低位放在内存的低位,数据的高字节放在内存的高字节。
大端字节序:
	数值的低位放在内存的高位,数据高位放在内存的低位。
两种字节序的优势
小端:
	因为低位在低字节,强制数据转换数据型时不需要再调整字节了。
大端:
	有符号数,其字节最高位不仅表示数据本身,还起到了符号的作用,符号位固定为第一个字节,
	也就是最高位占据最低地址,符号直接可以取出来,容易判断正负。
	最高位在最低地址,也就是说可以直接取到,不用在跨越几个字节,减少了时钟周期。
强制数据转换方式:
	在强制数据转换时,如果转换是由低精度转向高精度,这数值本身是没有变化的,如short是2字节,将其
	转换为4字节的int类型,无非是0x1234变成0x00001234,数值上是不变的,只是存储形式发生了变化,
	如果高精度转向低精度,这必然要丢失一些字节,编译器的转换原则是强制转换低精度类型,丢弃数值的高字节,
	只保留低字节,比如:0x12345678强制转换后0x5678。
	总结:
		低精度转高精度数值不变。
		高精度转低精度丢弃高字节保留低字节。
常见CPU字节序
大端字节序:IBM Sun PowerPC
小端字节序:x86 DEC
ARM体系则大小端字节序通吃,具体用那类字节序由硬件决定。
字节序不仅是CPU中内存的概念,也存在于文件存储和网络传输中,bmp格式文件是小端字节序,jpg则是大端字节序,
这些完全是按照设计者设计的。
网络字节序:网络字节序就是大端字节序。
BIOS中断/DOS中断/Linux中断的区别
事件:
	无论是保护模式还是实模式,在任何情况下都会有来自内部或者外部的事件发生,
	如果事件来自于CPU内部就被称为异常(Exception),比如CPU在计算时发现分母为0,就会抛出0异常。
	如果事件源于外部,也就是该事件由外部设备触发并通知CPU,这个事件就被称为中断。
中断向量表(Interrupt Vector Table IVT):
	BIOS和DOS都存在于实模式下的程序,它们建立的中断调用就是建立在中断向量表中的,它们通过软中断
	int中断号调用的。
	中断向量表中的中断向量大小为4个字节,这个4个字节描述了中断处理例程(程序)的段基址和段内偏移地址,
	因为中断向量表长度1024字节,最多只能容纳256个中断向量处理程序。
	计算机的启动之初中断向量表的中断例程是由BIOS建立的,它从物理内存的0x0000处初始化,并在中断向量表中添加
	各种处理例程。
BIOS为什么需要中断向量表:
	BIOS的中断向量表的主要功能是提供了硬件访问的方法,该方法是的对硬件的操作变得简单易行。
	BIOS是通过in/out指令来操作硬件写外设端口,BIOS中断向量表是处理硬件的。
	BIOS为什么添加中断向量表例程:
		1.给直接用避免重复性的某些代码,直接写成中断函数。
		2.给后来的程序用,如加载器boot loader,它们在调用硬件资源时就不需要自己写重复代码。
	BIOS如何填写中断向量表例程:
		BIOS在运行期间会扫描0xC0000到0xE0000之间的内存,若是在某个区域发现前两个字节都是
		0x55,0xAA时,意味着这片区域存在ROM代码的存在,在做该区域的累加和检查若结果与第3个字节
		的值相符,说明代码无误,从第4个字节进入,这个时候就开始执行硬件的自带的例程以及初始化硬件,
		最后BIOS填写中断向量表相关项。
	BIOS中断:
		中断向量表中的0H~1FH项是BIOS中断。
硬件操作
每个外设包括如显卡/硬盘等都有自己的内存,但是这种内存是只读存储器ROM,硬件的自己功能调用例程以及
初始化代码就存放在ROM中,根据规范第一个内存单元是0x55,第二个存储单元是0xAA,第三个存储单元应该就是rom中以
512字节为单位的代码长度,第四个存储单元就是实际代码了,直到第三个存储单元所示的长度为止。
CPU访问外设ROM的方式:
	1.内存映射:
		通过地址总线的方式将外设自己的内存映射到某个内存区域,并不是映射到主板上插的内存条中。
		物理内存中0xA0000开始到0xFFFFF这部分内存中一部分是专门用来做映射的,如果硬件存在,
		硬件自己的ROM会被映射到这片内存中的某处。
	2.端口操作:
		外设都有自己的控制器,控制器上有寄存器,这些就寄存器就是所谓的端口,通过in/out指令读写端口来访问硬件的内存。
DOS中断调用与BIOS中断调用与Linux中断
DOS运行在实模式下,建立的中断调用也是在中断向量表中,不过中断向量号不能跟BIOS的冲突。
0x20~0x27是DOS中断,因为DOS在实模式下运行因此可以调用BIOS中断。
DOS中断只占用0x21中断号,也就是DOS只有一个中断例程。
DOS中断调用实现:
	先向ah寄存器写好子功能号,再执行int 0x21,这时中断向量表中0x21表项即物理地址的0x21*4处的中断处理程序开始
	根据寄存器ah中的值来调用相应的子功能。
DOS中断总结:	
	1.DOS中断例程跟BIOS中断一样都存在于中断向量表IVT中
	2.0x20~0x27是DOS中断
	3.DOS中断只占用了0x21中断号,DOS只有一个中断例程
	4.寄存器ah值子功能号,执行int 0x21来调用相应的子功能

Linux中断:
	Linux是在进入内核之后才建立的中断例程,在保护模式下中断向量表已经不存在了,取而代之的是中断描述符(Interrupt Descriptor Table,IDT),
	在Linux下执行的中断例程是在中断描述符表中,已经不在中断向量表中了。
	Linux中断与DOS中断类似,Linux是通过int 0x80指令进入一个中断程序后再根据eax寄存器的值来调用不同的子功能函数,如果在实模式下执行
	int指令会自动访问中断向量表,如果在保护模式下运行执行int指令则会自动访问中断描述符。
	Linux中断总结:
		1.Linux中断与DOS中断类似
		2.Linux中断例程是在中断描述符中而非中断向量表
		3.Linux是通过int 0x80根据eax中的值来调用子功能函数
		4.在保护模式下int处理的是中断描述符IDT,实模式下是中断向量表IVT		
Section和Segment的区别
在汇编语言中语法关键字section或segment来表示一段区域,操作系统加载程序时并不关心节的数量和大小,
操作系统只关心节的属性,因为程序必然需要加载到内存中才能够运行,而内存的访问会涉及全局描述符表,
中断描述符的访问权限等属性,保护模式下任何任何对内存的操作都必须经过段描述符表。
section成为节是汇编语言中关键字section和segment修饰,逻辑划分的指令或数据区域汇编器会将这两个关键字
修饰的区域在目标文件编译成节,节最初诞生于目标文件中。
segment成为段,是链接器根据目标文件中属性相同的多个section合并后的section集合,这个集合被成为segment,也就是段。	
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

虚构之人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值