深度探索Linux操作系统:系统构建和原理解析(txt+pdf+epub+mobi电子书下载)


发布时间:2021-04-02 08:56:39

点击下载

作者:王柏生

出版社:机械工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

深度探索Linux操作系统:系统构建和原理解析

深度探索Linux操作系统:系统构建和原理解析试读:

前言

为什么要写这本书

真正认真开始学习计算机是在2000年,当时书店里到处充斥着一系列如“21天精通xxx”、“7天掌握xxx”之类的图书,更有甚者宣称“24小时学会xxx”。既是高科技,又这么容易学,谁会拒绝呢?于是我走上了这一行。最初,确实如这些书所说,只要按照书中描述,将类似于Visual Studio等IDE安装到机器上,然后像搭积木一样,拖拽几个控件,再添加几行代码,一个程序就完成了。

短暂的兴奋后,好奇心驱使我想更深层次地探索这一切是如何发生的。于是我开始关注更多的书籍、更多的文章、更多的编程参考,国内的、国外的。但是,结果让我很沮丧,如果依然是用积木来举例子,我发现它们的区别就像一盒10块的积木和一盒100块的积木,只有量的变化,没有质的区别。有人说Win32编程更底层,于是我抛开MFC,研究Win32编程。但是,结局一样让我失望。其实它们也没有本质区别,只不过如果把MFC比作大块积木,Win32是小块积木而已。其间我又遍寻那些Windows内幕的书进行研读,也是铩羽而归,似乎前方已无路可走……

2003年4月毕业后,我到了中科院软件所工作,开始从事与Linux相关的开发。经历了从Windows到Linux转型的阵痛后,我开始喜欢上了Linux,因为它是开源的,我似乎看到了曙光。于是我开始疯狂地购买Linux方面各种各样的书籍,阅读各种权威资料,基本上网络上各种权威专家推荐的书籍在我的书桌上全部可以找到。其中,绝大部分是关于内核源码分析的书,于是我一头扎进讲解内核源码分析的书中。但是我很快淹没在庞大的内核代码中,几次都到了难以坚持的程度,但是我强迫自己坚持,强制自己接受作者的灌输。但是,最终的结果是:看的时候似乎明白,但是看完后感觉又什么也没有看。现在回头看,当初很有点像“盲人摸象”这个典故所描述的,在我还没有看清整个“大象”的时候,我就直接去研究“大象”的某些部分的构造了。

彷徨中,我又看到了另外一条路,低版本的内核。我就像一个在沙漠中饥渴难忍的人突然看到了绿洲,我甚至将低版本的内核打印出纸版,然后就像拿着伟人语录一样,只要觅得空隙,就虔诚地潜心研读。但是这条新路除了代码量小了点,与之前的相比并没有太多本质的区别,而且还有一个致命的缺点——早期版本的内核不能和工作中使用的Linux很好地结合。

2005年,我从软件所被派到了中科红旗。最初从事桌面操作系统的开发,使用的是基于Qt的KDE,因为比较成熟,所以当时做得更多的是一些维护工作。但是在我的探索过程中依然重复着上面的故事,没有任何的起色。转折大概出现在2007年,Intel因为一个低功耗平台项目开始和中科红旗合作,他们要在低功耗平台上开发一套Linux操作系统,我接手了这项工作。因为这个平台的处理器性能相对要低,所以对于操作系统的要求比较高。同时因为用于消费类电子产品,用户体验要求也与普通的PC环境完全不同。所以,基于已有的桌面系统几乎是不可能了。于是,我们开始从头开发和定制。

这个从零开始的过程,让我彻底认识了整个Linux操作系统,而不仅仅是Linux的内核。曾经对内核中很多做法和模块不明了,通过构建整个操作系统,我豁然开朗。比如,内核中的DRM模块,其全称是Direct Rendering Manager,从字面上看是直接渲染管理,这到底是什么意思?如果你仅仅从内核的角度来理解,相信我,你永远也不能正确理解它。恰恰是在构建系统时,亲手组装和调试图形环境,包括X、OpenGL、2D/3D图形驱动,让我明白了DRM的用途。这样的例子举不胜举。

经过这个过程中,我深刻认识到,学习操作系统,有三件最重要的事:第一是实践,第二依然是实践,第三还是实践。老祖宗说“纸上得来终觉浅”,唯物主义者说“实践是检验真理的唯一标准”,两句话中都蕴含着同一个道理——追求真理离不开实践。只是阅读、分析源码还远远不够,我们要动手实践,从实践中学习,实践反过来再促进思考。而且,实践也使学习不再是一个枯燥乏味的负担,而是一个乐趣。

通过这个过程,我也体会到,即使只为了学习内核,也不能将目光全部放在内核上。从整个操作系统的角度,从各个组件间关系的角度理解内核,效果反而更好。当对整个系统有了深入的理解后,再去理解组成操作系统的各个组件,会事半功倍。一旦从总体上理解了系统,你就会“艺高人胆大”,就可以尽情地“折腾”Linux系统了,因为每一个组件尽在你的掌握之中。而恰恰在这不断的“折腾”中,理论又得到不断的提高,从此进入一个良性循环。

很早我就想把这种方法整理成书,和更多的读者分享,希望帮助所有有志于操作系统、又尚在门外徘徊的年轻人少走些弯路。但是因为忙于生计,只能在有限的业余时间写作,所以直到2013年中期,才基本把整个书稿写完。

对于计算机而言,操作系统的重要性不言而喻,但它也是我们心中的痛,我将为此求索一生。如果有生之年没能成功,请将我埋在后来者脚下。

读者对象

对于如同笔者一样怀揣操作系统梦的爱好者,希望本书能帮他们顺利地迈进操作系统这扇门;对于正在或者准备学习操作系统理论的大学生,本书将帮助他们感性地触摸那些“高居庙堂之上”的抽象理论;对于高级读者,本书中的很多内容对他们也很有用处,比如动态链接部分的讨论、Linux图形原理部分的讨论等。

除了以上的读者外,本书适合以下相关从业人员阅读:

◆ 系统程序员。要想成为一个合格的系统程序员,操作系统和编译链接技术是必不可少的技能,本书对此有较深入的讨论。

◆ 嵌入式Linux工程师。作为一名嵌入式Linux工程师,应该知道如何使用交叉编译工具链、配置编译内核、裁剪系统、搭建图形系统,甚至定制桌面环境,这些相关知识读者在本书中都可以找到。

◆ Linux发行版工程师。作为制作发行版的工程师,更需要彻底熟悉操作系统的每个组件以及组件间的关系,本书可以满足他们这方面的需求。

◆ Linux应用开发工程师。对于应用开发程序员,也推荐阅读本书,因为越深入地理解操作系统和编译链接原理,就越能写出高效而简洁的程序。

如何阅读本书

本书围绕着构建一个完整的Linux操作系统这一主线展开,除了第1章外,其余各章环环相扣,所以请读者严格按照章节顺序阅读。

工欲善其事,必先利其器。尤其是对于这样一本实践丰富的书来说,工作环境是后续内容的基础。因此,第1章介绍了如何准备工作环境。但是类似安装Linux发行版这样的内容,相关参考随处可见,因此书中并没有浪费篇幅去一一介绍,而是仅仅指出其中需要特别注意之处。

工具链是后面进行构建的基础,因此,接下来在第2章中构建了工具链。工具链是整个操作系统中非常重要的一部分,理解工具链的工作原理,对理解操作系统至关重要,所以第2章中并没有仅仅停留在构建的层次,还通过探讨编译链接过程,讨论了工具链的组成以及各个组件的作用。

在第3章和第4章,我们从零开始,构建了一个具备用户字符界面的最小操作系统。同时在第5章,我们从更深层次的角度探讨了这一切是如何发生的。我们从内核的加载、解压一直讨论到用户进程的加载,包括用户空间的动态链接器为加载程序所做的努力。

在第6章和第7章,我们首先构建了系统的基础图形系统,然后在其上构建了桌面环境。在第8章,我们深入探讨了计算机图形的基础原理,讨论了2D和3D程序的渲染、软件渲染、硬件渲染,我们也从操作系统的角度审视了Pipeline。

笔者强烈建议读者在真实的计算机上安装一个Linux操作系统,让它成为你日常的工作机。然后将书中的,尤其是与实践相关的所有命令实际运行一遍。之后再尝试脱离本书,自己争取从头再构建一遍,相信你一定会在这个过程中受益匪浅的。

勘误和支持

由于作者水平有限,加之编写时间仓促,书中难免会出现一些错误或者不准确的地方,恳请读者提出宝贵意见,批评指正。来信请发送至邮箱baisheng_wang@163.com,笔者会尽自己最大的努力给出回复。

致谢

首先感谢恩师李明树先生,是他将我带进了操作系统这扇大门。

感谢机械工业出版社华章公司的策划杨福川,在他身上我看到了专业精神,这也是我在与几个出版团队沟通后,毫不犹豫地决定请他们出版的原因。

感谢机械工业出版社华章公司的姜影编辑,她清晰的思路让我深深折服。每每在遇到困惑不知如何表达时,她都能通过简单的几句话点醒梦中人。

感谢我的父母,感谢他们的养育之恩。感谢我的哥哥,为了让我受到更好的教育,在他刚刚毕业不久,就顶着生活的压力,将我从农村接到了城里接受教育,为我的学业奔波操劳。感谢我的嫂子在生活上给予我的无微不至的照顾。把最后一份感谢留给我的妻子,是她在我工作这些年,承担了照顾父母、操持家务的重任,是她的无私付出让我能全身心地投入到工作和学习中。王柏生北京第1章准备基本环境

在开始Linux操作系统的探索旅程之前,我们首先需要准备一下环境,读者最好在真实的计算机上安装一个Linux操作系统作为工作机。毫无疑问,使用是最好的学习方法,如果日常工作系统也是Linux,那么这无疑有助于更好地理解Linux操作系统。但是这不是必须的,也可以安装一台虚拟机作为工作机。鉴于现在的Linux发行版的安装过程非常友好和自动化,本章无意浪费版面介绍其安装过程。

另外,在构建操作系统时,需要频繁重启系统,因此强烈建议读者不要使用工作机作为实验机,而是另外安装一台虚拟机作为实验机。本章将介绍如何创建一个虚拟的裸机以及如何在其上安装Linux操作系统,并且介绍为了后面的开发和调试,在虚拟机上需要进行的一些必要的准备。

因为桌面环境可以利用一个模拟的小X服务器Xephyr来调试,所以我们可以先在宿主机的Xephyr上进行开发和调试,然后再到构建的真实系统上调试。因此,本章的最后一部分介绍了如何使用Xephyr。1.1 安装VirtualBox

笔者建议在真实的计算机上安装一个Linux操作系统,这个系统作为工作机,主要进行编译、构建和开发,另外辅助提供做一些实验及阅读源代码等。理论上使用哪家的发行版或者哪个版本都可以,但是为了避免意外的麻烦,建议使用和笔者相同的环境。在写作这本书的最后,笔者使用Ubuntu12.10将构建过程全部验证了一遍,所以建议读者也使用这个版本。

另外,我们当然不希望使用工作机调试我们构建的操作系统,因为这样需要频繁的启动。所以我们需要一个虚拟机,笔者使用的虚拟机是VirtualBox。在Ubuntu12.10下,使用如下命令安装VirtualBox:

因为我们是从零开始构建系统,因此虚拟机上还需要一个额外的Linux系统作为桥梁。鉴于其只是一个桥梁,所以使用什么版本没有关系,比如笔者虚拟机上使用的是Ubuntu11.10。1.2 创建虚拟计算机

在安装Linux操作系统之前,我们需要从硬件层面创建一个虚拟的计算机。VirtualBox启动后,主界面如图1-1所示。图 1-1 VirtualBox主界面

单击图1-1中VirtualBox主界面工具条中的“新建”按钮,新建虚拟机的向导将启动。这个过程非常简单,读者按照新建向导一路执行下去就好。读者只需要注意在安装过程中要选择安装Linux操作系统,其他全部默认即可。

创建好虚拟机后,在VirtualBox主界面中将出现新建的虚拟裸机,如图1-2所示,其中,ubuntu11.10就是笔者新创建的虚拟机。1.3 安装Linux系统

本节我们将在1.2节创建的裸机上安装Linux操作系统。

在图1-2所示的工具栏上单击“设置”按钮,当然要确保在左侧的列表中选中的是刚刚创建的裸机,出现如图1-3所示的界面。图 1-2 新建的虚拟裸机图 1-3 载入虚拟光盘映像

在图1-3中,首先在左侧的列表中选择“存储”。在默认情况下,我们会看到虚拟机已经添加了一个空的虚拟光驱。如果VirtualBox没有自动添加,读者手动添加即可。至于是SATA接口还是IDE接口,是没有关系的,毕竟是虚拟的。然后,选中虚拟光驱,即图1-3所示的IDE控制器下的“没有盘片”,然后单击“分配光驱”文本框旁的带有光盘图片的按钮。VirtualBox将打开一个文件选择对话框,读者找到Linux操作系统的光盘映像即可。这个过程与我们将物理光盘放入光驱道理完全相同。

在将光盘映像放入虚拟光驱后,在图1-2所示的界面中单击工具栏上的“启动”按钮,启动Linux系统的安装过程。鉴于现在的发行版的安装过程非常友好且全程自动化,我们就不再浪费太多版面逐一介绍。其中需要读者重点关注的是一定要从硬盘中为我们即将构建的系统划分出一块分区,基本上2GB就足够了,并将其格式化为EXT4类型,当然后面这一步也可以在系统安装完成后进行。

在安装过程中,在选择安装类型(installation type)这一步,务必要选择"Something else",如果选择了使用中文简体安装,这里显示的可能是“其他选项”,总之,要选择这个允许我们为硬盘分区的选项,如图1-4所示。图 1-4 选择安装类型

单击图1-4中的继续(Continue)按钮,将出现硬盘分区的界面。基本上划分两个分区就可以了,一个用来安装操作系统,另外一个作为“实验田”,留给我们构建的操作系统用于实验。划分好的分区大致如图1-5所示。图 1-5 硬盘分区

另外,还有一处需要提醒读者,在安装的后期,安装程序可能会通过网络更新系统,因为这个虚拟机上的系统只是一个桥梁,没有太多工作要做,一个基本的系统就足够了,所以完全没有必要浪费时间等待其下载更新,直接略过(skip)即可。1.4 使用root用户

很多发行版由于安全原因,默认使用普通用户登录,因此当要执行一些需要特权的操作时,往往需要通过"sudo"命令使自己临时成为root用户。但是这对于我们希望研究操作系统的人来说,当然有点不方便了,所以,笔者建议使用root用户登录。

既然打算使用root用户,当然要知道root用户的密码了,但是Ubuntu默认的root用户密码是什么呢?不必理会这个问题,直接改成我们自己的即可。以普通用户登录虚拟机后,启动一个终端,执行如下命令修改root用户密码:

然后就可以使用root用户了,或者使用命令"su"切换用户,或者登录时使用root用户。1.5 启用自动登录

在安装步骤中,在添加用户这一步的界面中,有一个可选项,即“自动登录”(log in automatically),这个选项默认是没有选中的。如果没有选中,那么在启动时,每次登录都需要输入登录密码,非常麻烦。所以,建议读者开启自动登录。

如果安装时没有选中,也不必重新安装。读者可以修改登录管理器lightdm的配置文件lightdm.conf,在其中添加下面一行:

如果读者实在不愿意敲击键盘输入这几个字母,那么可以在系统设置中,打开“用户账户”(User Accounts),将普通账户的“自动登录”(Automatic Login)开启,然后在配置文件lightdm.conf中将多出类似下面一行:

读者将其中的普通用户的登录名改为root即可。

如此,即可免除每次登录时输入密码之苦,也无需手动切换用户,而是自动以root身份登录。1.6 挂载实验分区

假设在虚拟机上为构建的操作系统划分的分区是/dev/sda2,那么我们使用如下命令将其挂载在根目录的vita下:

为了避免每次开机后都需要手工挂载,我们将其写入fstab文件中,开机后由操作系统自动挂载:1.7 安装ssh服务器

我们使用ssh服务从宿主系统向虚拟机复制构建的实验系统。因此,在虚拟机系统上需要安装ssh服务器。ssh服务器需要通过网络从源服务器下载。以笔者使用的VirtualBox版本为例,默认其为虚拟机开启了网络,并且使用的是NAT模式,要访问互联网,无需设置IP、路由等,但是要自己设置DNS。或者直接可以进入设置,将虚拟机的网络改为桥接模式,这样在DHCP的网络环境中,无须做任何修改即可访问互联网。

确保虚拟机可以访问互联网后,我们就可以安装ssh服务器了。当然首次从源安装软件时,需要更新源。更新源和安装ssh服务的命令如下:1.8 更改网络模式

在VirtualBox的各种网络模式中,允许宿主机和虚拟机通信的常用网络模式是桥接模式和Host-Only模式。但是桥接模式有两个问题,一个是宿主机一定要时刻连网,因为在桥接模式下,虚拟机在局域网内被模拟为与宿主机同等地位的一台主机,所以如果宿主机没有接入局域网,何谈虚拟机和宿主机通信?虽然现在网络很普及,但是毕竟会存在未接入网络的情况。另外一个问题是,我们也不想让开着ssh服务器的虚拟机暴露在互联网上。所以,笔者建议虚拟机的网络使用Host-Only模式,设置方法如图1-6所示。图 1-6 设置虚拟机网络模式

在图1-6中,首先选中左侧列表中的“网络”,然后将“连接方式”更改为"Host-Only"模式。

确定后,宿主系统将多出一个网络接口,用于与虚拟机通信,默认一般是vboxnet0,其地址被设置为192.168.56.1,虚拟机的地址被设置为192.168.56.101。当然读者可以自己修改,但是这没有任何必要。

然后在虚拟机上我们就可以使用如下命令启动ssh服务器了:

在宿主系统上,我们可以远程登录到虚拟机,命令如下:

也可以将宿主系统的文件(比如a)复制到虚拟机,命令如下:1.9 安装增强模式

当没有安装增强模式时,虚拟机只能使用固定的分辨率,那么可能不支持全屏这样的功能。如果需要全屏功能,可以选择安装VirtualBox的增强功能来解决这一问题。

在VirtualBox的菜单中,首先选择“设备”菜单;然后在下拉菜单中选择“安装增强功能”。

增强功能也在一个光盘映像中,所以如果是首次安装增强功能,VirtualBox将首先从网络上下载这个光盘映像到宿主机。下载完成后,这个光盘映像一般会被自动装入到虚拟光驱,如果没有自动挂载,需要读者手动将其放入到虚拟光驱,然后,运行其中的"VBoxLinuxAddtions.run"即可。当然如果是为Windows系统安装增强功能,需要运行相应的Windows版本。1.10 使用Xephyr

在宿主系统上使用Xephyr调试桌面环境,要更方便一些。所以这一节,我们介绍如何在宿主系统上调试桌面环境。如果尚未安装Xephyr,则首先通过如下方法安装Xephyr:

然后使用如下命令启动Xephyr:

在另外的终端中,将Display定向到Xephyr:

如此,在这个终端中,所有需要X服务器渲染程序都将使用Xephyr。当然,为了方便,我们可以开启任意个终端,并将它们的Display都定向到Xephyr。

比如我们可以在一个终端中运行窗口管理器winman:

在另外一个终端中运行任务条:

而在第三个终端中运行Desktop程序:

图1-7就是在笔者的宿主机上运行winman以及一个gedit后的Xephyr。图 1-7 Xephyr第2章工具链

软件的编译过程中由一系列的步骤完成,每一个步骤都有一个对应的工具。这些工具紧密地工作在一起,前一个工具的输出是后一个工具的输入,像一根链条一样,因此,人们也把这些工具的组合形象地称为工具链。

在本书中,我们将从源码开始,逐步构建一个基本的Linux操作系统。显然,工具链是我们首先需要考虑的,因为工具链是编译包括内核在内的操作系统各个组件的基础。正所谓“物有本末,事有终始,知所先后,则近道矣。”因此,在本章中,我们并没有匆忙切入正题——构建工具链,而是首先结合具体的例子,借助宿主系统中的工具,尽可能地将工具链的工作过程更具体地展示给读者。希望通过这个探讨过程,读者可以明白工具链包含哪些组件以及这些组件的基本工作原理。然后基于GNU工具链的源码,手工从源码构建一套工具链。后面,我们将会使用这一章构建的工具链编译内核以及操作系统的各个组件。2.1 编译过程

在Linux系统上,通常,只需使用gcc就可以完成整个编译过程。但不要被gcc的名字误导,事实上,gcc并不是一个编译器,而是一个驱动程序(driver program)。在整个编译过程中,gcc就像一个导演一样,编译过程中的每一个环节由具体的组件负责,如编译过程由cc1负责、汇编过程由as负责、链接过程由ld负责。

我们可以通过传递参数"-v"给gcc来观察一个完整的编译过程中包含的步骤,下面是一个典型的编译过程中gcc的输出信息,为了更清楚地看到编译过程中的主要步骤,对输出信息进行了适当删减。

根据gcc的输出可见,对于一个C程序来说,从源代码构建出可执行程序经过了三个阶段:(1)编译

gcc调用编译器cc1进行编译,产生的汇编代码保存在目录/tmp下的文件ccYBInzt.s中。(2)汇编

gcc调用汇编器as,汇编编译过程产生汇编文件cca2nBio.s,产生的目标文件保存在目录/tmp下的文件ccj54pkM.o中。(3)链接

我们看到,gcc并没有如我们想象的那样直接调用ld进行链接,而是调用collect2进行链接。实际上,collect2只是一个辅助程序,最终它仍将调用链接器ld完成真正的链接过程。举个例子,对于C++程序来说,在执行main函数前,全局静态对象必须构造完成。也就是说,在main之前程序需要进行一些必要的初始化,gcc就是使用collect2安排初始化过程中如何调用各个初始化函数的。根据链接过程可见,除了main.c对应的目标文件ccj54pkM.o外,ld也链接了libc、libgcc等库,以及所谓的包含启动代码(start code)的启动文件(start/startup file),包括crt1.o、crti.o、crtbegin.o、crtend.o和crtn.o。

事实上,对于C程序来说,编译过程也可以拆分为两个阶段:预编译(或称为编译预处理)和编译。所以,软件构建过程通常分四个阶段:预编译、编译、汇编以及链接,如图2-1所示。图 2-1 C程序的构建过程

在接下来讨论编译过程的章节中,如无特殊说明,都将以下面的程序为例。

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载