RSS订阅信息安全技术跟踪与研究:技术、平台、会议、论文、产业
你现在的位置:首页 / 技术积累 / 正文

操作系统概念理解与答疑

0 技术积累 | 2016年8月1日
转载申明:本站原创,欢迎转载。但转载时请保留原文地址。
原文地址:http://www.vonwei.com/post/OSviewAb.html

   操作系统将重复的工作集中化,并建立自己的管理机制

         学习操作系统,要目标明确,不能偏离轨道,特别是不要太过纠结于硬件内部的工作原理,对于硬件只要认为给其一个输入,其会给我们一个输出就行。

         访问硬件的两种方式:(1)将外设内存映射到一定范围的地址空间,与物理内存的访问一致;(2)通过I/O接口访问,CPU访问I/O接口的寄存器(或者称为端口)就可以操作外设。

         关于用户态和内核态:用户态和内核态是对于CPU来讲的,指CPU运行在特权3级,还是特权0级,并不是对用户进程。当应用程序陷入内核态,自己实际已经不在CPU上运行了,其context已经被保存到特权级栈中,此时CPU上运行的是内核程序了。

         关于系统调用:应用程序通过系统调用来使用OS的特权级别功能,配合完成进程任务。编译器提供了一套标准库函数,已经封装好了系统调用(代码已经写死了系统调用号,如0x80)。

         程序分段的作用:(1)为了代码重定位,平移整个段到任何位置,只要将段基址寄存器中的地址改变,程序照样准确运行;(2)将大内存分为可以访问的小段,早期寄存器是16位的,一个段最多可以访问到64KB,而早期内存再小也有1MB(需要20位),分段将段基址乘以16(左移4位)加上16位的段内偏移地址,就可以访问20位的空间了。

        

         汇编语言中,程序员可以为自己的程序分段(代码段、数据段、栈段、bss段等),灵活编排布局;而高级语言(如C语言)一般不允许程序自己分段,而是由编译器(如gcc)代劳了,编译器会自动编译出适合操作系统加载运行的程序,操作系统会将各个段分配到不同的物理内存。

         编译器、操作系统和CPU三者配合才能对程序保护,检测出指令中的违规行为:(1编译器负责挑选数据具备的属性,根据属性将程序片段分类,如划分出只读属性的代码段和可写属性的数据段,注意编译器并没有让段具备某种属性,只是将相同属性的数据归类在一起,如对于代码段,编译器将程序中有关代码的多个sections合并为一个大的Segment(就是所谓的代码段),编译器并没有为代码段添加额外信息。(2操作系统通过设置GDT全局描述符表来构建段描述符,在段描述符中指定段的位置、大小和属性,注意OS才是真正给段添加属性的地方,如将代码段设置为只读属性。(3CPU中的段寄存器提前被操作系统赋予相应的选择子,从而确定指向的段,在执行指令时,会根据该段的属性来判断指令的行为,判断是否异常。

         CPU只会执行cs:ip中的指令,这两个寄存器记录下一条待执行的指令地址,那程序内指令是如何连续不断执行的?首先,指令是连续紧凑的,即指令全部排在一起,形成一片连续的区域,即代码段;其次,每条指令的大小实际是由其操作码决定的,即CPU拿到每条指令的操作码,就知道实际指令所占的大小了,这样通过当前指令地址+当前指令长度=下一条指令地址即可自动获取到指令。

         程序分段和内存分段:程序中的段只是软件中人为逻辑上的划分,用于不同数据的归类;内存分段指的是处理器为了访问内存而采用的机制,即内存分段机制。不过程序中的段可以用CPU中的段寄存器直接指向它们,然后用内存分段机制可以访问到程序中的段。因此,程序中的段是内存中的内容,而内存分段机制是访问内存的手段。

         实模式:“段基址+段内偏移地址”经过段部件的处理,直接输出物理地址;

         保护模式:通过段选择子GDT中找到相应的段描述符(记录了段的起始、大小等信息),得到段基址;段基址+段内偏移地址经过段部件处理得到线性地址,线性地址(虚拟地址)进一步通过CPU页部件转换得到物理地址。

         注意两种模式下的段基址区别:实模式下,段基址就在默认的段寄存器中;而保护模式下,段基址在默认段选择子寄存器指向的段描述符中。实模式和保护模式下,转入段寄存器的不一样,一个是真正的段基址,一个是段选择子(Selector)。常见段寄存器:代码段寄存器CS,数据段寄存器DS,附加段寄存器ESFSGS,堆栈段寄存器SS

         对于32CPU,段寄存器无论在16位实模式,还是32位保护模式,都使用同一组段寄存器,而且在32位保护模式下的段选择子也是16位宽度,因此csds等段寄存器位宽都是16位。

         另一个角度:实模式下,16位段寄存器存储的是真实的段地址;而保护模式下,16位的段寄存器无法放下32位的段地址,而是存储下16位的段选择子,段基地址只好存放在一个叫做描述符表(Descriptor)的表中。

 

         不同操作系统的差异:可执行程序格式不一样,如Linux下是ELFExecutable and Linking Format)格式(readelf命令可以查看相关信息);Windows下是PEPortable Executable)格式。另外系统调用、API、编译器、标准库等也不一样,使得Linux系统的应用程序无法在Windows下运行。

 

         变量、参数与堆栈全局变量通常放在数据段中,谁都可以访问;局部变量会放在自己的栈中,可以随时清理,只有自己用,放在数据段会浪费空间。函数参数也放在栈区,一方面是只有这个函数用自己的参数,体现局部性,不必放在数据段浪费空间;另一方面,函数是在执行过程中调用(动态调用),编译时无法预测,所需内存空间无法确定。

         汇编语言比C语言快的真相:高级语言如C为了通用性,往往会加入一些额外代码,编译出来的汇编代码比较多,不如用汇编语言直接,相当于最后生成的机器指令,C语言会多了一些看似没用的指令,导致比直接用汇编慢,因此并不是汇编语言本身快。快不快看指令数目和CPU自身。

 

         解释型程序与编译型程序的区别:解释型语言如JavaScriptPythonShell等,本身是文本文件,脚本中的代码不会真正去CPU上执行,而是作为脚本解释器的输入,脚本解释器才是真正在CPU上执行,解析作为输入的脚本语言,并动态根据关键字和语法做出相应的行为。而编译出来的程序,运行时本身就是一个进程。实际上脚本解释器就是编译型程序。

 

         大端和小端:内存以字节为单位读写,如果只处理一字节的数据类型char,无需担心大端和小端,但是对于占用4字节的int型数据等,大端和小端时各字节在物理内存中存放的顺序是不一样的。小端是数据低位在低地址,强制转换数据类型时不需要调节字节;大端是高位在低地址,对于有符号数,其高位还起到符号作用,符号固定在第一字节,可以直接取出来,容易判断正负。

         常见CPU的字节序列IBMSUNPowerPC是大端;x86DEC是小端;ARM大小端通吃,由硬件选择;网络字节序通常是大端,在x86架构上程序发送网络数据时,要注意转换字节顺序。

 

         中断BIOSDOS都是存在于实模式下的程序,BIOS中断和DOS中断调用都是建立在中断向量表IVTInterrupt Vector Table)中的,通过软中断指令int中断号来调用。Linux内核在进入保护模式后才建立中断例程,在保护模式下,中断向量表已经不存在了,取而代之的是中断描述符表IDTInterrupt Descriptor Table)。因此,实模式下执行int指令,会自动访问中断向量表IVT,而保护模式下执行int指令,则会自动访问中断描述符表IDT

 

         SectionSegment的区别C程序大体分为预处理、编译、汇编和链接四个阶段。预处理器将高级语言中的宏展开,去掉代码注释,为调试器添加行号等;编译器将预处理后的高级语言进行词法分析、语法分析、语义分析、优化,最后生成汇编代码;汇编器将汇编代码编译成目标文件,即转换成目标平台上的机器指令;链接器将目标文件连接成可执行文件。

         汇编代码中,通常用section或者segment表示一段区域,汇编器会将其在目标文件中编译成section节,链接器将多个目标文件中的section节进行合并,将属性相同的section节合并为一个大的section集合,称为segment段,这就是可执行程序中的代码段和数据段了。操作系统加载程序时(加载器使用ELF中的program header显示的段),并不关心section节的数量和大小,为所有权限属性相同的节(即合成了段)分配不同的段选择子,从而指向段描述符,实现不同的访问权限

 

         控制CPU下一条指令:通过程序计数器PC,不同处理器实现方法并不相同。x86体系的CPU中(如IntelAMD),程序计数器PC并不是单一的某个寄存器,而是段寄存器CS和指令寄存器IP的组合,即CS:IP,使用mov指令一次只能改变一个寄存器,无法同时改变CSIP的值,可能会导致错误,不过存在一些专门改变执行流的指令,如jmpcallintret,在硬件级别实现了同时改变cpip的原子操作。ARM的程序计数器只有个专门的寄存器,即PC,想要改变程序流,可以直接使用mov赋值

 

         指令集和体系结构:常见的movadd等指令名是给人看的,方便编程,CPU实际只认编码,目前的CPU指令无论是哪种指令集,都有操作码和操作数两部分组成。通过人为规定一个格式,规定操作码和操作数的大小与位置,然后在CPU硬件电路中写死这些规则,让CPU在硬件一级上识别这些格式,从而能识别出操作码和操作数。

         最早的指令集是复杂指令级计算机CISCComplex Instruction Set Computer),指令集比较复杂,后来出了精简高效的指令集RISCReduced Instruction Set Computer)。IntelAMD等常用的x86 CPU是基于CISC的,而MIPSARMPowerC6000等都采用RISC指令体系。MIPS处理器时业界公认最优雅的,龙芯用的也是MIPS指令集。

 

         主引导记录MBRMBR全称Main Boot Record,存在于整个硬盘最开始的那个扇区(001扇区),这是约定好的固定位置,BIOS会将该位置的MBR引导程序加载到物理地址0x7c00,然后开始执行MBR,引导权交给MBRMBR的任务是把控制权交给操作系统加载器,MBR扇区除了引导程序外,还有64字节大小的分区表,记录了分区信息,标记为活动分区的约定好意味着该分区存在操作系统,内核加载器的入口地址也约定好固定在各个分区最开始的扇区,称为OBROS Boot Record)扇区。注意,整个硬盘只有1MBR,可以有多个OBR(如一个硬盘上安装多个操作系统时)。

参考:《操作系统真象还原》,郑钢著


  • ------------------分隔线----------------

  • 如果感兴趣,欢迎关注本站微信号,跟踪最新博文信息,手机微信扫一扫下面的二维码,即可关注!
  • 微月信公众号
  • 推荐您阅读更多有关于“ 操作系统   ”的文章

    请填写你的在线分享代码
    上一篇:PC与MSP430G2553通过UART通信编程实践下一篇:主引导记录MBR的运行

    猜你喜欢

    评论列表:

    发表评论

    必填

    选填

    选填

    必填,不填不让过哦,嘻嘻。

    记住我,下次回复时不用重新输入个人信息

    本站介绍
    最近发表
    本年最热文章
    本月最热文章
    网站分类
    文章归档