浅谈OS及build过程

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

浅谈OS及build过程—byArmand********************************************************************************************InstructionContentasbelow:1、长久以来的一些疑问2、计算机系统层次3、OS功用(文件系统&&进程调度&&进程与线程)4、build的过程ByArmand/12August2013*********************************************************************************************长久以来的一些疑问曾经缠着一个助教问很多问题,当时是因为刚接触Armlinux,没有了跑裸机时的‘一眼望到底’的快感和掌控感,对很多事情都想搞明白所以然来,你用鼠标click一下,到结果呈现在屏幕上,中间到底发生了什么?他就推荐我读一本叫《程序员的自我修养》,现在终于有时间好好阅读一下,顺便记下笔记,以备长久之用。相信它会在操作系统、编译原理方面给我带来长足的进步。慢慢从底层往上走这是趋势,而计算机专业的同学从上层往底层走就痛苦多了,要抓住这次机会,持续更新这一系列文档,直到我的知识结构发生变化,就像下图一样,打通:浅谈OS及build过程—byArmand一个大牛曾经说过:体系结构、汇编、C语言、操作系统,永远都是编程大师们的护身法宝,如同少林寺的《易筋经》,学会了之后将无所不能。不知你是否也有下面的疑问?C/C++程序如何被编译成目标文件,程序在目标文件中如何存储?目标文件又如何被linker链接在一起形成可执行文件(符号处理、重定位、地址分配)可执行文件如何被装载并执行?可执行文件与进程的虚拟空间之间如何映射?什么是动态链接,为什么需要动态链接?什么是堆、栈?什么是运行库、系统调用?如果上面的知识结构能够打通,那么相信这些问题也就不是问题了,go!计算机系统层次计算机科学领域的所有问题都可以通过增加中间层的方式解决。跟通信协议中的分层相似,下层为上层提供服务,并规定服务的申请规则,即定义接口标准(interface)。计算机系统层次也不例外如下:其中除了硬件和应用之外的所有层次均可称之为中间层。浅谈OS及build过程—byArmand应用程序调用系统API,linux下的glibc库提供Posix标准的API,而window下则是win32标准的API。设备驱动屏蔽了硬件,它可以看作是内核的一部分,设备驱动的机制和接口并不是由硬件厂商规定的,这是OS的机制,硬件厂商只负责驱动的实现。glibc是gnu发布的libc库,即c运行库。glibc是linux系统中最底层的api,几乎其它任何运行库都会依赖于glibc。glibc除了封装linux操作系统所提供的系统服务外,它本身也提供了许多其它一些必要功能服务的实现。由于glibc囊括了几乎所有的UNIX通行的标准,可以想见其内容包罗万有。而就像其他的UNIX系统一样,其内含的档案群分散于系统的树状目录结构中,像一个支架一般撑起整个作业系统。在GNU/Linux系统中,其C函式库发展史点出了GNU/Linux演进的几个重要里程碑,用glibc作为系统的C函式库,是GNU/Linux演进的一个重要里程碑。分享函式库群,这是glibc的主体,分布/lib与/usr/lib中,包括libc标准C函式库、libm数学函式库、libcrypt加密与编码函式库、libdb资料库函式库、libpthread行程多执行绪函式库、libnss网路服务函式库....等等。这些都是可分享函式库,档名都以.so做结尾。在Linux平台上最广泛使用的C函数库是glibc,其中包括C标准库的实现,也包括本书第三部分介绍的所有系统函数。几乎所有C程序都要调用glibc的库函数,所以glibc是Linux平台C程序运行的基础。glibc提供一组头文件和一组库文件,最基本、最常用的C标准库函数和系统函数在libc.so库文件中,几乎所有C程序的运行都依赖于libc.so,有些做数学计算的C程序依赖于libm.so,以后我们还会看到多线程的C程序依赖于libpthread.so。以后我说libc时专指libc.so这个库文件,而说glibc时指的是glibc提供的所有库文件。glibc并不是Linux平台唯一的基础C函数库,也有人在开发别的C函数库,比如适用于嵌入式系统的uClibc。讲到标准C库,其实很多C语言的书里都用了大篇幅来讲解标准C库,我认为这是不对的!!这样就降低了大家C语言本身特性的关注度,特别是对于做嵌入式的人来说,很多IDE里根本就没有完整标准C库,一本书读下来,就前几章有用。从网上找了一段话,认为比较有用。C标准主要由两部分组成,一部分描述C的语法,另一部分描述C标准库。C标准库定义了一组标准头文件,每个头文件中包含一些相关的函数、变量、类型声明和宏定义。要在一个平台上支持C语言,不仅要实现C编译器,还要实现C标准库,这样的实现才算符合C标准。不符合C标准的实现也是存在的,例如很多单片机的C语言开发工具中只有C编译器而没有完整的C标准库。浅谈OS及build过程—byArmandOS的功用操作系统有两个大的功能:一是提供抽象的接口(即通过库来提供系统服务),使得开发变得高效,二是管理硬件资源,是它们运行得高效。它创建了一套管理制度(算法),使系统运行便捷、高效、有序。所以,如果能全部搞明白操作系统的管理思想,你就成为了一个出色的管理者。所以,当嵌入式平台的配置越来越高,自然就转向了操作系统,它比前后台系统拥有无可比拟的优势。当arm开发转向了LINUX,不但嵌入式平台上运行的是linux,连我们的开发环境也是在linux上进行的,主要的原因是在编译内核等等开发步骤上,linux平台提供了完整的GUN工具链,还有一个重要的原因是嵌入式linux是经过剪裁的linux,本质上并没有变化,做linux开发连linux环境都不熟的话怎么行?你的电脑上的主要部件正好对应OS的主要功能硬件是死的,比如,CPU就只负责执行指令,你的PC指针指向哪,在clock的驱动下,PC就不断地依次执行哪里的指令。所以要进行进行调度,无论是分时还是基于优先级,压栈、出栈、安排任务都是OS的事,所有的应用程序都以进程的方式运行在比操作系统更低的级别,每个进程都有自己独立的地址空间,并相互隔离。CPU由OS统一分配,无论优先级高低都会有机会获得CPU的使用权,可以想象,系统从一堆半导体器件到如此有序、高效的运行,OS肯定做了海量的工作。我们的硬盘的结构层次:硬盘--盘面--磁道--扇区。文件系统保存了这些文件的存储结构(仓库与货物清单)并负责维护这些数据结构,同时保证磁盘中的扇区能有效地组织利用。而操作系统内核需要做的是拥有文件系统的操作方式(相当于驱动),这就是我们说的OS支持的文件系统。这样在某个文件系统挂载之后才能正确的读写。现在有一个8kbytes的文件test.datlinux的ext3文件系统可能是这样存储它的:sector1000-1007共4096bytes浅谈OS及build过程—byArmand2000-2007共3094bytes现在要读它,read系统调用,(内核)文件系统受到read请求后,判断出所在扇区的位置,调用硬盘驱动发出读硬盘的指令(一般是读写I/O端口寄存器)内存在计算机中是仅次于CPU的第二宝贵的资源,支持多任务之后,如何将有限的物理内存高效地分配给多个程序使用成了OS的紧要任务—内存管理。假如一台电脑的内存大小为128M,程序运行所需的内存空间连续。现在有A和B两个任务,A任务需要10MB的运行内存,B任务需要100MB的运行内存,最简单的分配方式是直接分配给他们共110M内存。但是这样的坏处是地址不隔离,即程序直接访问物理内存,在程序遭到恶意修改后,很容易访问到不属于自己的内存空间,造成系统故障,影响其他程序的运行。内存的使用效率很低。程序运行的地址不确定,给编程带来了困难。因为它访问数据和指令跳转时目标地址在链接生成可执行文件的时候就确定了,这就涉及到重定位的问题。所以!增加中间层!把程序给出的地址看做是虚拟的,然后经过分配空间之后形成的映射表变成实际的物理地址。当程序访问的地址空间超过分配的空间时直接看做是异常给拒绝掉。这样地址隔离的问题就解决了。单纯的使用映射机制(分段),解决了第一个和第三个问题,但是映射机制以程序(进程)为单位,内存不足的时候,被换入换出的都是整个可执行程序,这样就会进行大量的磁盘访问,影响速度,效率低下。根据程序的局部性原理,在某个时间段,只频繁的引用了一小部分数据,我们使用分页机制来解决这个问题。将地址空间等分成固定大小的页。CPU硬件本身支持整页读写,多种页大小可选。目前几乎多有的PCOS都选择4KB大小的页。分页就是说,将程序分成若干页,但不全部调入内存,运行时当所需的页不在内存当中时,会发生页错误,操作系统接管该进程,并把所需的页从磁盘调入内存。如下页图:虚拟存储的实现需要依靠硬件—MMU浅谈OS及build过程—byArmand进程与线程线程(thread)又称为轻量级进程(LWP,lightweightprocess),是程序执行的最小单元,一个进程由多个线程组成,各线程共享程序的内存空间(代码段、数据段、堆)及一些进程级的资源(打开文件、信号)浅谈OS及build过程—byArmand简析Build的过程在linux中,由源码生成可执行文件:预编译删除所有#define展开所有宏定义处理所有的条件预编译指令如:#if,#ifdef,#else,#elif,#endif等#ifdef标识符程序段1#else程序段2#endif它的作用是:当标识符已经被定义过(一般是用#define命令定义),则对程序段1进行编译,否则编译程序段#if表达式程序段1#else程序段2#endif它的作用是:当指定的表达式值为真(非零)时就编译程序段1,否则编译程序段2。可以事先给定一定条件,使程序在不同的条件下执行不同的功能。浅谈OS及build过程—byArmand处理所有的#include,将被包含的文件出入到该指令的位置。原来只是插入!!我说呢,很多疑问解决了,.c也可以插入!在使用前用extern声明与在头文件中声明是一样的!头文件中define也是可用的!条件编译防止重复插入!删除所有的注释添加行号和文件名标示保留所有的#pragma编译器指令,因为编译器需要使用它们。在所有的预处理指令中,#Pragma指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作编译:对预处理的文件进行:词法分析、语法分析、语义分析,优化后生成汇编代码。词法分析是将源代码经过scanner,分离成一个个token:关键字、标识符、字面量(数字、字符串)和特殊符号(+=等)。有专门的一个程序叫lex来完成这项工作,当你创建了一种编程语言,没必要自己写词法分析器,只需要把规则传递给lex即可。然后用语法分析器对记号进行语法分析,产生语法树(以表达式为节点的树)。语法分析也有一个叫yacc的程序完成。在完成语法分析之后,编译器也不了解这些语句的含义。在语义分析中,整个语法树被标上类型,如果需要隐式转换,则语义分析程序会在语法树上插入相应的转换节点。然后会经过相当多的优化,源码级的优化,然后生成目标代码(汇编代码),目标代码优化。现代编程语言本身的特性就非常复杂,就像C++语言的定义十分复杂,至今也没有一个编译器能完整的支持它的语言标准规定的所有特性。加上现代CPU采用了流水线、多发射、超标量等技术,使优化过程也很复杂。汇编:就是将汇编代码翻译成机器码链接:为什么有链接呢,这是代码工程发展到一定程度的产物,如果一个工程只有一个源码文件是不需要链接。当工程分了很多模块,各自完成相应功能,相互调用(头文件相当于在画

1 / 9
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功