马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
盘算机体系
大作业
题 目 步伐人生-Hello’s P2P
专 业 生物信息学
学 号 2021112920
班 级 2103401
学 生 zhm
指 导 教 师 sxjx
盘算机科学与技术学院
2023年4月
摘 要
本文章用拟人形象化的语言,同时兼具科学严谨的术语与逻辑,讲述了一个Hello步伐的一生。以一个简单的C语言步伐为切入点,用生动形象的语言说明白一个步伐从预处置惩罚,编译,汇编,链接,到进程出现,存储管理,输入输出,进程回收等方面。全面细致的讲述了一个C步伐的生命周期,目标是加强对盘算机体系的理解,从而以后能面向体系编写更好的步伐。
关键词:关键词1;关键词2;……;
(择要0分,缺失-1分,根据内容精彩称都酌情加分0-1分)
目 录
第1章 概述................................................................................................................ - 4 -
1.1 Hello简介......................................................................................................... - 4 -
1.2 环境与工具........................................................................................................ - 4 -
1.3 中间结果............................................................................................................ - 4 -
1.4 本章小结............................................................................................................ - 4 -
第2章 预处置惩罚............................................................................................................ - 5 -
2.1 预处置惩罚的概念与作用........................................................................................ - 5 -
2.2在Ubuntu下预处置惩罚的命令............................................................................. - 5 -
2.3 Hello的预处置惩罚结果解析................................................................................. - 5 -
2.4 本章小结............................................................................................................ - 5 -
第3章 编译................................................................................................................ - 6 -
3.1 编译的概念与作用............................................................................................ - 6 -
3.2 在Ubuntu下编译的命令................................................................................ - 6 -
3.3 Hello的编译结果解析..................................................................................... - 6 -
3.4 本章小结............................................................................................................ - 6 -
第4章 汇编................................................................................................................ - 7 -
4.1 汇编的概念与作用............................................................................................ - 7 -
4.2 在Ubuntu下汇编的命令................................................................................ - 7 -
4.3 可重定位目标elf格式.................................................................................... - 7 -
4.4 Hello.o的结果解析.......................................................................................... - 7 -
4.5 本章小结............................................................................................................ - 7 -
第5章 链接................................................................................................................ - 8 -
5.1 链接的概念与作用............................................................................................ - 8 -
5.2 在Ubuntu下链接的命令................................................................................ - 8 -
5.3 可执行目标文件hello的格式........................................................................ - 8 -
5.4 hello的假造地址空间..................................................................................... - 8 -
5.5 链接的重定位过程分析.................................................................................... - 8 -
5.6 hello的执行流程............................................................................................. - 8 -
5.7 Hello的动态链接分析..................................................................................... - 8 -
5.8 本章小结............................................................................................................ - 9 -
第6章 hello进程管理....................................................................................... - 10 -
6.1 进程的概念与作用.......................................................................................... - 10 -
6.2 简述壳Shell-bash的作用与处置惩罚流程........................................................ - 10 -
6.3 Hello的fork进程创建过程......................................................................... - 10 -
6.4 Hello的execve过程..................................................................................... - 10 -
6.5 Hello的进程执行........................................................................................... - 10 -
6.6 hello的异常与信号处置惩罚............................................................................... - 10 -
6.7本章小结.......................................................................................................... - 10 -
第7章 hello的存储管理................................................................................... - 11 -
7.1 hello的存储器地址空间................................................................................ - 11 -
7.2 Intel逻辑地址到线性地址的变动-段式管理............................................... - 11 -
7.3 Hello的线性地址到物理地址的变动-页式管理.......................................... - 11 -
7.4 TLB与四级页表支持下的VA到PA的变动................................................ - 11 -
7.5 三级Cache支持下的物理内存访问............................................................. - 11 -
7.6 hello进程fork时的内存映射..................................................................... - 11 -
7.7 hello进程execve时的内存映射................................................................. - 11 -
7.8 缺页故障与缺页停止处置惩罚.............................................................................. - 11 -
7.9动态存储分配管理........................................................................................... - 11 -
7.10本章小结........................................................................................................ - 12 -
第8章 hello的IO管理.................................................................................... - 13 -
8.1 Linux的IO装备管理方法............................................................................. - 13 -
8.2 简述Unix IO接口及其函数.......................................................................... - 13 -
8.3 printf的实现分析........................................................................................... - 13 -
8.4 getchar的实现分析....................................................................................... - 13 -
8.5本章小结.......................................................................................................... - 13 -
结论............................................................................................................................ - 14 -
附件............................................................................................................................ - 15 -
参考文献.................................................................................................................... - 16 -
第1章 概述
1.1 Hello简介
P2P:From Program to Process,指源文件到可执行文件,可执行文件到进程的一系列过程。首先是用高级语言编写的源文件,GCC编译器读取hello.c文件,预处置惩罚器cpp转化为hello.i修改后的源步伐,然后编译器ccl再编程hello.s汇编语言,之后汇编器as将其变为hello.o可重定位目标步伐,是二进制编码。最后链接器ld将可重定位目标步伐与标准C库链接,最后生成了可执行步伐。
然后再shell中./hello,shell就会对读入的字符串进行解析,发现是可执行文件后会调用fork函数去分配一个子进程给hello。之后会调用execve函数去分配内存,初始化等等,跳转地址等等。然后从.rodata只读段读取到hello world而且输出到屏幕上。Hello的生命便被创建了。
020:From Zero-0 to Zero-0,指hello的生命从0开始,最后归于0,hello进程的一切都是shell fork出来的,shell会先为hello清算出一片假造内存,保存好原来的寄存器状态之后给hello全新的寄存器。,。设置步伐计数器按序执行步伐。CPU为hello给出了寄存器,分别了逻辑控制流,开辟了一条条新的流水线,I/O输出了hello语句,RAM为hello备好了数据。待到hello执行返回后,shell父进程会回收掉hello,回收掉其占用的内存寄存器等等,内核会从操作体系中删掉hello的陈迹,hello就这样来无影去无踪,是020的。
1.2 环境与工具
I7 11800H+Ubuntu 20.04 LTU
1.3 中间结果
hello.i 预处置惩罚之后文本文件
hello.s 编译之后的汇编文件
hello.o 汇编之后的可重定位目标步伐
hello 链接之后的可执行目标文件
hello.objdmp Hello.o 的反汇编代码
helloo.objdmp Hello 的反汇编代码
hello.elf Hello.o 的 ELF 格式
helloolf Hello 的 ELF 格式
1.4 本章小结
通过阅读hello的自白,形象的感受了hello颠末编写、预处置惩罚、编译、汇编、链接和执行等阶段进程。说明白盘算机体系在让一个步伐运行差别的构成部门,一个进程P2P,020,体现了其中间状态,以及盘算机分层次处置惩罚步伐的头脑
(第1章0.5分)
第2章 预处置惩罚
2.1 预处置惩罚的概念与作用
(以下格式自行编排,编辑时删除)
预处置惩罚是指步伐源代码在被翻译成目标代码的过程中,生成二进制文件之前的预备过程,预处置惩罚器会读取#开头的内容,修改源步伐,将头文件的内容插入到步伐文本中,最后得到hello.i文件。
根据宏定义#define将步伐中对应的宏进行更换
针对#ifdef等进行条件编译
将#include的头文件进行复制,添加到源代码中,提高编程模块性
整体的作用就是便于接下来编译器的编译
2.2在Ubuntu下预处置惩罚的命令
图表 1 Ubuntu下预处置惩罚命令
图表 2:Hello的预处置惩罚结果解析
大量头文件被引入
图表 3:标准库中引用的外部函数
以及一些文件位置信息
2.4 本章小结
本章节分析了从hello.c到hello.i预处置惩罚的过程,先容了预处置惩罚的概念和作用。而且本身利用命令对文件进行了预处置惩罚操作,而且实验读取解析预处置惩罚文件的内容,分析预处置惩罚到底进行了什么变化。
(第2章0.5分)
第3章 编译
3.1 编译的概念与作用
- 编译的概念:将与处置惩罚好的高级语言文本转换成执行同样操作的汇编语言的过程
- 编译的作用:盘算机无法理解高级语言,所以要把高级语言转化为更简单的汇编语言,机器才有大概把其转化为机器语言。编译器ccl将hello.i翻译成hello.s。同时如果有语法错误就会报错输出提示信息。
3.2 在Ubuntu下编译的命令
图表 4:Ubuntu下编译的命令
3.3 Hello的编译结果解析
3.3.1 数据
可以看到%rbp-20是argc,数据argc保存的位置得到
图表 5:argc
下面是i的赋值,发现循环变量i存放在%rbp-4,局部变量都是存在内存里
图表 6:i存入内存
从上面也能看到立即数用4开头表现
字符串数据存在.LC0段中,保存在.rodata中
图表 7:字符串数据
打印的时候也体现了
图表8:字符串数据打印时体现
循环变量i赋初值为0
图表 9:赋值
循环变量i++操作
图表 10:算术操作
对返回值的修改操作
图表 10:对返回值的修改操作
用leaq进行盘算赋值变址寻址,将存储在.rodate节中的printf语句的格式串传递给寄存器%rdi作为调用printf函数的参数
图表11:leaq操作
这个是argc!=4的语句,不即是4就跳到后面
图表12:不即是语句
循环控制中的i<9语句
If的条件判断
图表 13:if判断
满足if条件则次序执行,要是不满足,则相称,则跳转到L2,L3,不执行if内的操作
For循环
图表 14:for判断
For的主题在L4内,如果符合循环条件就跳到L4中执行循环体
Exit函数:
参数:传递参数寄存器%edi值为1
函数调用:通过指令call 调用exit函数
函数返回:无返回
图表 15:Exit函数
Printf函数:
参数:argv[1]和argc[2]的地址或字符串参数首地址
函数调用:在if条件判断执行体与for循环执行体之中被调用。
函数返回:无返回
图表 16:Printf函数
Sleep函数:
参数:传递参数寄存器%edi值为atoi后的返回值rax
函数调用:通过指令call 调用sleep函数
函数返回:无返回
图表 17:Sleep函数
Main函数:
参数:argc和argv,对应的寄存器分别为%rdi和%rsi。
函数调用:体系启用函数__libc_start_main通过利用call语句来调用main函数,call指令将下一条指令的地址dest压入栈中,然后跳转至main函数执行。
函数返回:return,0为main函数的正常返回指令。即把0设置到rax然后竣事
图表 18:Main函数
Getchar函数
参数:无参数
函数调用:通过指令call 调用getchar函数
函数返回:无返回
图表 19;Getchar函数
这里用atoi转换
图表 20:范例转换操作
把array转换成int,然后传到sleep中当参数
3.4 本章小结
本章中我们重要了解了编译的概念和作用,学习了编译的相干指令。我们还细致的对汇编文件hello.s进行了分析。分析了其中的数据存储,赋值,运算,函数调用,控制转移,关系操作等等。我们对汇编语言有更深的理解,可以读懂汇编语言中的信息,了解了C到汇编语言之间的关系。
(第3章2分)
第4章 汇编
4.1 汇编的概念与作用
汇编器将hello.s语言翻译成机器二进制指令语言,结果保存在hello.o中。hello.o为二进制文件。我们打开是乱码的
将人类能读懂的汇编语言进一步抽象,转换为机器能读懂的二进制代码,而且是可重定位的二进制目标文件
4.2 在Ubuntu下汇编的命令
图表21:Ubuntu下汇编的命令
图表22:生成ELF
4.3.1 ELF头
下图是elf可重定位目标文件的格式。ELF头以一个16字节的序列开始,这个序列形貌生成了该文件的体系的字的巨细和字节次序。ELF头剩下的部门包罗辅助链接器分析语法息争释目标文件信息。其中包括ELF头的巨细、目标文件的范例(如可重定位、可执行大概共享的)、机器范例(如x86-64)、节头部表
的文件偏移,以及节头部表中条目标巨细和数量。差别节的位置和巨细是由节头部表形貌的,其中目标文件中每个节都有一个固定的巨细的条目。
图表 23:ELF头
差别节的内容存储在ELF头和节头表之间的位置
一样平常节头表都包罗以下几个部门
.text:已编译步伐的机器代码
.rodata:只读数据,比如printf语句中的格式串和开关语句中的跳转表
.data:已初始化的全局和静态C变量。局部局部C变量在运行的时候保存在栈中,既不出如今.data节中,也不出如今.bss节中。
.bss:未初始化的全局和静态C变量,以及所有被初始化为0的全局或静态C变量。在目标文件中这个节不占用现实的空间,它仅仅是一个占位符。目标文件格式区分已初始化和未初始化变量是为了空间效率:在目标文件中,未初始化变量不必要占据任何现实的磁盘空间。运行时,在内存中分配这些变量,初始值为0。
.symtab:一个符号表,它存放在步伐中定义和引用的的函数和全局变量的信息。一些步伐员错误地认为必须通过-g选项来编译一个步伐,才华得到符号表信息。现实上,每个可重定位目标文件在.symtab中都有一张符号表。然而,和编译器中的符号表差别,.symtab符号表不包罗局部变量的条目。
.rel.text:;一个.text节中位置的列表,当链接器把这个目标文件和其他文件组合时,必要修改这些位置。一样平常而言,任何调用外部函数大概引用全局变量的指令都必要修改。另一方面,调用本地函数的指令则不必要修改。注意,可执行目标文件并不必要重定位信息,因此通常忽略,除非用户显示地指示链接器包罗这些信息。
.rel.data:被模块引用大概定义的所有全局变量的重定位信息。一样平常而言,任何已初始化的全局变量,如果它的初始值是一个全局变量地址大概外部定义函数的地址,都要被修改。
.debug:一个调试符号表,其条目时步伐中定义的局部变量和范例定义,步伐中定义和引用的全局变量,以及原始的C源文件。只有以-g选项调用编译器驱动步伐时,才会得到这张表。
.line:原始C步伐中的行号和.text节中机器指令之间的映射。只有以-g选项调用编译器驱动步伐时,才会得到这张表。
.strtab:一个字符串表,其内容包括.symtab和.debug节中的符号表,以及节头部中的节名字。字符串表就是以null末端的字符串的序列。
下图是本步伐的节头表
图表 24:本步伐的节头表
4.4 Hello.o的结果解析
objdump -d -r hello.o 分析hello.o的反汇编,并请与第3章的 hello.s进行对照分析。
图表 25:反汇编结果
图表26:反汇编结果
Hello.o反汇编与hello.s对比分析,得到以下内容:
- 机器语言是有操作码,操作数,尚有内存,寄存器编号等等数字构成的
- 机器语言是由汇编语言一一对应映射而来的,汇编语言现实上是机器语言用人类能懂的方式书写,机器语言还添加了重定位条目等更细节的信息,便于厥后步伐的生成。
但是也有差别:
- 汇编语言的跳转是用编号表现的,而机器指令中利用相对位置,即目标地址和下一条指令头部的偏移量来表现的。
下图为机器指令的跳转
图表 27:机器指令的跳转
下图为汇编指令的标号跳转
图表 27:汇编指令的标号跳转
- 汇编利用函数名称进行函数调用,而机器指令更明确的用地址进行函数调用
下图为机器指令的函数调用,而且可以看到后面全为0,由于这些是库中的函数,要等到动态链接后才华确定函数的地址。
下图为机器指令的函数调用
图表 28:机器指令的函数调用
下图为汇编的函数调用
图表29:汇编的函数调用
- hello.s中的操作数时十进制,hello.o反汇编代码中的操作数是十六进制。机器编码中还存在巨细端的差别。
- 机器指令中有重定位条目,但是汇编hello.s中没有
图表 30:机器指令中的重定位条目
- 机器反汇编每条语句都有对应的编号,按照字节排序生成的,而汇编则没有
图表 31:机器反汇编语句对应编号
6. 分支转移,汇编语言只有转移到标号,没有详细的地址,而机器语言有详细的地址偏移量形貌
下图为机器语言中的分支转移
图表 32:机器语言中的分支转移
下图为汇编语言中的分支转移
图表33:汇编语言中的分支转移
4.5 本章小结
本章我们把汇编语言源步伐利用汇编器汇编成了可重定位的目标文件。分析了可重定位目标文件的elf格式,elf头、节头表、符号表等内容,理解了汇编后的二进制可重定位代码。了解了重定位条目信息,当重定位形成可执行文件之后,就会在对应的位置填入相应的数据。
除此以外,我们还利用objdump工具把hello.o文件反汇编为了汇编语言,然后分析了机器语言反汇编形成的汇编语言与hello.s的差别之处。发现了机器语言和汇编语言的差别与映射关系,以及机器语言会留下动态链接的标记,为进一步处置惩罚做预备。
(第4章1分)
第5章 链接
5.1 链接的概念与作用
链接(linking)是将各种代码和数据片段收集并组合成为一个单一文件的过程,这个文件可被加载(复制)到内存中并执行。链接可以执行于编译时,也就是在步伐被加载器加载到内存并执行时;甚至执行于运行时,也就是由应用步伐来执行。
链接器在软件开辟中扮演着一个关键的脚色,由于他们使得分离编译成为大概。我们不消将一个大型的应用步伐构造为一个巨大的源文件,而是可以把它分解为更小、更好管理的模块,可以独立地修改和编译这些模块。当我们改变这些模块中的一个时,只必要简单地重新编译它,并重新链接应用,而不是重新编译其他文件。
总而言之,链接将多个模块化,可复用的小代码段大概库,动态的合成到我们编写的步伐中,这样可以综合的利用功能的同时确保代码量不会很大,不会占用许多的空间。
5.2 在Ubuntu下链接的命令
链接命令;
ld -o hello -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o hello.o /usr/lib/x86_64-linux-gnu/libc.so /usr/lib/x86_64-linux-gnu/crtn.o
图表34:Ubuntu下链接的命令
5.3 可执行目标文件hello的格式
下图是ELF头和节头表
图表35 :ELF头和节头表
由ELF头可以看出,整个步伐的种类变成了EXEC可执行文件
再看节头表,可以发现其声明白hello中的所有section信息,包括步伐中的size和offset,所以可以根据Section Headers中的信息利用HexEdit定位每个被占用的section在区间(起始位置,巨细),其中Address是步伐在假造地址处加载的起始地址。
比如我们看到只读内存段如下图
图表 36:只读内存段
Rodata段的地址是0x402000,巨细是0x3c
Data段的地址是0x404048,巨细是0x4
图表 37:Data段
等等信息,我们都可以从ELF头分析得到
除此以外,由于可执行文件是被完全链接的,因此也没有了rel节。
分析hello的ELF格式,用readelf等列出其各段的根本信息,包括各段的起始地址,巨细等信息。
5.4 hello的假造地址空间
图表 38:edb加载hello步伐
图表 39:查看符号
图表 40:一致性
和节头表对比,interp都在0x4002e0。其他的节都在这附近,比如init段存在于0x401000
rodata段在0x40404 ,可以看到用edb说明白我们的步伐加载到了正确的地址空间。
5.5 链接的重定位过程分析
- 符号解析,目标文件.o定义和引用符号,每个符号都对应这一个全局变量大概静态变量大概一个函数。
其中函数和已初始化的全局变量大概静态变量是强符号,未初始化的全局变量大概静态变量是弱符号;然后根据链接的符号规则,为每个符号开辟相应的存储空间与赋值。从而每个符号都能得到一个准确的映射定义
- 重定位,编译器和汇编器生成的代码段和数据段的开始地址都是0。而链接器给每个符号都映射了一个内存地址,这样对符号的操作就是对相应的内存空间的操作。
链接器通过汇编器生成的重定位条目来进行重定位操作。
所以可执行文件是根据重定位条目重定位后的,没有重定位条目,都确定好了位置。Hello.o必要保存重定位条目供后续链接利用。链接的本质是把差别的节归并,如果文件交织利用差别的符号,便必要把这些符号链接在一起。
下图是hello反汇编的结果。
图表 41:hello反汇编结果
可以看到有以下差别点
- 地址长度差别,地址内容差别,在未链接的文件中只是简单的利用相对偏移量,而链接后的文件中则是利用假造地址空间中的地址。
下图是左未链接右链接后对比,可以看到右边是有假造地址显示的
图表42:对比
- 未链接时找不到一些库函数的定义,但是在链接后我们都可以看到调用的库函数
下图时部门调用的库函数展示
图表 43:调用库函数展示
比如我们看库函数atoi的重定位
图表 44:库函数atoi的重定位
图表45:盘算过程
假造地址盘算结果就是e8后跟着的偏移量。利用call语句时的pc值盘算偏移量跳转到atoi假造地址位置便是重定位过程
- 所有的重定位条目都被修改消散了,由于变成了确定的运行时内存地址
图表 46:edb执行
用step运行如下:
- ld-2.27.so!_dl_start 0x7fce 8cc38ea0
- ld-2.27.so!_dl_init 0x7fce 8cc47630
- hello!_start 0x400500
- libc-2.27.so!libc_start_main 0x7fce 8c867ab0
- -libc-2.27.so!__cxa_atexit 0x7fce 8c889430
- -libc-2.27.so!__libc_csu_init 0x4005c0
- hello!_init 0x400488
- libc-2.27.so!_setjmp 0x7fce 8c884c10
- -libc-2.27.so!_sigsetjmp 0x7fce 8c884b70
- –libc-2.27.so!__sigjmp_save 0x7fce 8c884bd0
- hello!main 0x400532
- hello!puts@plt 0x4004b0
- hello!exit@plt 0x4004e0
- *hello!printf@plt –
- *hello!sleep@plt –
- *hello!getchar@plt –
- ld-2.27.so!_dl_runtime_resolve_xsave 0x7fce 8cc4e680
- -ld-2.27.so!_dl_fixup 0x7fce 8cc46df0
- –ld-2.27.so!_dl_lookup_symbol_x 0x7fce 8cc420b0
- libc-2.27.so!exit 0x7fce 8c889128
5.7 Hello的动态链接分析
当步伐调用一个有共享库定义函数时,编译器无法预测函数运行地址,所以采用一种延迟绑定的技术,让步伐执行时才对共享链接库进行绑定。动态链接器用GOT和PLT实现动态链接,GOT中存放的时函数的目标地址,PLT则利用GOT的条目进行目标函数跳转。
而根据hello的ELF文件可知GOT起始表位置为0x404000,如下图。
图表 47:GOT起始表位置
然后我们用edb去查看项目变化
上图是动态链接前
图表 48:动态链接后
上图是动态链接后
可以看到dl_init前0x404000是后面有一大串0的,在动态链接后,这些0全部都被更换成了链接后的值。
5.8 本章小结
链接器的出现便于模块化编程,分块编程,独立的编译,链接在一起。有效的节流了步伐员的工作量,便于维护代码的同时节流了内存。也由此产生了库函数,便于编写步伐。本章偏重分析了链接的过程,区分了链接前后步伐的异同,了解了链接的原理与步骤。而且对于我们hello步伐生命在链接这个部门,利用反汇编,edb等工具,做了详细剖析,对于步伐的生成有了更深入的理解。
(第5章1分)
第6章 hello进程管理
6.1 进程的概念与作用
- 进程的概念
- CSAPP上解释shell为一个交互的应用型步伐,它代表用户运行其他步伐。Shell被称为“壳”,给用户提供了操作页面,接受命令然后调试相应的进程。
狭义上,进程是正在运行步伐的实例,而广义上,进程是一个具有独建功能的步伐关于某一组数据的依次运行。操作体系执行的根本单元就是一个进程。进程既是根本的分配单元,也是根本的执行单元。
每个进程都有本身的pid,也有本身的地址空间与数据,包括文本区域、数据区域和堆栈。文本区域存储处置惩罚器执行的代码。而数据存储在进程执行期间动态分配的内存区域中,堆栈区域则管理者调用的指令和本地变量。进程只有在步伐被shell调用执行,CPU给予其生命时才成为一个活动的实体
当代操作体系运行一个进程,我们得到了一个假象就是步伐独占了整个计统,包括处置惩罚器和内存,但是事实上,我们只是在上下文中不停的切换进程来维持着这个假象。进程为应用步伐提供了两种形象,一种是独立的逻辑控制流,一种是私有地址空间。提高CPU执行效率,减少因步伐等候造成的CPU空闲和其他盘算机软硬件资源的浪费。
6.2 简述壳Shell-bash的作用与处置惩罚流程
- Shell首先从命令行找出特殊字符,将空格,逗号,冒号等字符翻译成间隔符号,把命令行分割成一小条语句的集合
- 解析命令行,而且把命令行参数传递给execve函数和argv参数
- 然以这些语句集合会被处置惩罚,查抄其中是否有shell的关键字
- 如果不是关键字,则查抄路径下是否有相应的可执行步伐
- 如果既不是可执行步伐也不是关键字,则输出相应的错误提示信息
- 如果是可执行步伐,则利用fork函数创建相应的子进程
- 在子进程中,继承之前的步骤获取参数,而且执行步伐
- 如果是shell的内置指令,则执行
- 对于命令行末尾有&则代表创建的是前台工作,利用waiotpid等候工作返回
- 如果没有&代表是配景工作,shell返回。
6.3 Hello的fork进程创建过程
图表 49:fork进程创建过程
此时bash首先会搜索这是否是一个内置命令,结果不是,那么shell就会在磁盘上开始搜索,找到hello的步伐,然后为他分配相应的内存空间而且调入
接着bash会利用fork函数创建子进程。子进程和父进程有相同的假造地址空间副本,但是相对于父进程是独立的。每个进程都是有相同的本地变量值尚有相同的用户栈。父进程和子进程的区别就是pid差别。
Fork函数会调用一次返回两次,在子进程中返回值是0.在父进程中返回的是子进程的pid号。因此我们可以区分步伐的部门是在父进程中进行还是子进程中进行。
6.4 Hello的execve过程
Fork函数并没有执行hello,hello的执行是由execve进行的
Execve 函数,如果成功执行则不返回,如果失败则返回-1
可执行目标文件由execve函数加载运行,即hello步伐被赋予生命了。只有当出现错误时,才会返回到调用步伐通知他。
Bash首先会调用启动代码,从而设置栈而且将控制传递给主函数。当main开始执行时,用户栈被分配给步伐,用户栈的大致布局如下,从栈底到栈顶:
栈底的是参数和环境字符串,往上是null末端的指针数组,指向的是环境变量字符串,全局变量environ指向这些指针中的第一个envp[0]。环境变量指针数组后的是argv数组,指向的是参数字符串。栈的顶部是体系启动函数libc_start_main的栈帧,之后便是为main函数分配的栈帧了。
6.5 Hello的进程执行
上下文信息的概念:
上下文就是内核重新启动一个被抢占的进程所必要的状态。它由一些对象的值构成,这些对象包括通用目标寄存器、浮点寄存器、步伐计数器、用户栈、状态寄存器、内核栈和各种内核数据布局,比如形貌地址空间的页表、包罗有关当前进程信息的进程表,以及包罗进程已打开文件的信息的文件表。
进程时间片的概念:
进程时间片是分时操作体系分配给每个正在运行的进程微观上的一段CPU时间(在抢占内核中是:进程程开始运行直到被抢占的时间)。当代操作体系答应同时运行多个进程 ,即并行。
但是在一个CPU的情况下,前配景的进程不大概同时进行没那么就是差别的进程抢占差别的时间片,时间片在不停分配给差别的进程切换,从而看起来这些进程在同时运行。
进程调度的概念:
进程调度是由内核控制安排的,在进程执行的某些时刻,内核可以决定抢占当前进程,并重新开始一个先前被抢占了的进程。当内核调度一个新的进程后,就会抢占当前进程,而且被给予一个新的时间片,这便是上下文切换
图表 50:上下文切换
用户态和焦点态的概念:
Hello步伐一开始是运行在用户状态下,是不能够执行内核代码的。但是如果遇到了异常,便可以切换到内核模式,异常步伐会调用内核体系代码,等到执行完毕后,内核模式又会切换为用户模式,如果大概的话,继承执行hello步伐。进程上下文切换也是在内核模式完成的。
图表 51:查看进程
6.6 hello的异常与信号处置惩罚
hello出现的异常:停止,陷阱(即体系调用)
hello产生的信号:SIGINT、SIGTSTP、SIGCONT、SIGCHLD
我们在执行hello步伐时,利用键盘CtrlC发送一个终止信号SIGINT
图表 52:发送SIGINT
当我们用CtrlZ暂停进程后,发送SIGSTP,可以发现hello进程仍旧存在
图表 53:发送SIGSTP
图表 54:ps查看
Jobs查看:
图表 55:jobs查看
Pstree:
图表 56:进程树
Kill:
图表 57:发送信号SIGCONT
6.7本章小结
进程给我们一种多个步伐同时运行的抽象,提高了盘算机的性能开释。我们通过这章的学习,了解到了进程的根本概念,原理,和用户模式和内核模式,上下文切换,信号,四大异常,fork函数等等。我们通过详细的剖析本身linux假造机上的hello步伐的运行
(第6章1分)
第7章 hello的存储管理
7.1 hello的存储器地址空间
逻辑地址:又称相对地址,是步伐运行由CPU产生的与段相干的偏移地址部门。他是形貌一个步伐运行段的地址。
物理地址:步伐运行时加载到内存地址寄存器中的地址,内存单元的真正地址。他是在前端总线上传输的而且是唯一的。在hello步伐中,他就表现了这个步伐运行时的一条确切的指令在内存地址上的详细哪一块进行执行。
线性地址:这个和假造地址是同一个东西,是颠末段机制转化之后用于形貌步伐分页信息的地址。他是对步伐运行区块的一个抽象映射。
结合hello说明逻辑地址、线性地址、假造地址、物理地址的概念。
7.2 Intel逻辑地址到线性地址的变动-段式管理
在段式存储管理中,将步伐的地址空间分别为若干个段(segment),这样每个进程有一个二维的地址空间。在前面所先容的动态分区分配方式中,体系为整个进程分配一个一连的内存空间。而在段式存储管理体系中,则为每个段分配一个一连的分区,而进程中的各个段可以不一连地存放在内存的差别分区中。
步伐加载时,操作体系为所有段分配其所需内存,这些段不必一连,物理内存的管理采用动态分区的管理方法。在为某个段分配物理内存时,可以采用首先适配法、下次适配法、最佳适配法等方法。在回收某个段所占用的空间时,要注意将收回的空间与其相邻的空间归并。段式存储管理也必要硬件支持,实现逻辑地址到物理地址的映射。
步伐通过分段分别为多个模块,如代码段、数据段、共享段:可以分别编写和编译;可以针对差别范例的段采取差别的保护;可以按段为单位来进行共享,包括通过动态链接进行代码共享。这样做的长处是:可以分别编写和编译源步伐的一个文件,而且可以针对差别范例的段采取差别的保护,也可以按段为单位来进行共享。
总的来说,段式存储管理的长处是:没有内碎片,外碎片可以通过内存紧缩来消除;便于实现内存共享。缺点与页式存储管理的缺点相同,进程必须全部装入内存。
7.3 Hello的线性地址到物理地址的变动-页式管理
在这个转换中要用到翻译后备缓冲器(TLB),首先我们先将线性地址分为VPN(假造页号)+VPO(假造页偏移)的形式,然后再将VPN拆分成TLBT(TLB标记)+TLBI(TLB索引)然后去TLB缓存里找所对应的PPN(物理页号)如果发生缺页情况则直接查找对应的PPN,找到PPN之后,将其与VPO组合变为PPN+VPO就是生成的物理地址了。
7.4 TLB与四级页表支持下的VA到PA的变动
首先在TLB中查找PTE,若能直接找到则直接得到对应的PPN,详细的操作是将VPN看作TLBI和TLBT,前者是组号,后者是标记,根据TLBI去对应的组找,如果TLBT能够对应的话,则能够直接得到PTE,进而得到PPN。
图表 58:地址转换
其中若是在TLB中找不到对应的条目,则应去多级页表中查找,VPN被分为了四块。有一个叫做CR3的寄存器包罗L1页表的物理地址,VPN1提供到了一个L1
PET的偏移量,这个PTE包罗L2页表的基地址,VPN2提供到一个L2
PTE的偏移量。依次类推,最终找到页表中的PTE,得到PPN。
而VPO和PPO相称,最终的PA即是PPN+PPO。
7.5 三级Cache支持下的物理内存访问
得到物理地址之后,先将物理地址拆分成CT(标记)+CI(索引)+CO(偏移量),然后在一级cache内部找,如果未能寻找到标记位为有效的字节(miss)的话就去二级和三级cache中寻找对应的字节,找到之后返回结果。
图表 59:三级Cache物理内存访问
7.6 hello进程fork时的内存映射
mm_struct(内存形貌符):形貌了一个进程的整个假造内存空间
vm_area_struct(区域布局形貌符):形貌了进程的假造内存空间的一个区间
在用fork创建假造内存的时候,要经历以下步骤:
创建当前进程的mm_struct,vm_area_struct和页表的原样副本
两个进程的每个页面都标记为只读页面
两个进程的每个vm_area_struct都标记为私有,这样就只能在写入时复制。
图表60:fork时的内存映射
7.7 hello进程execve时的内存映射
加载hello并执行必要以下几个步骤:
1.删除已存在的用户区域。删除当前进程假造地址的用户部门中的已存在的区域布局(即mmap指向的vm_area_structs)。
2.映射私有区域。为新步伐的代码、数据、bss和栈区域创建新的区域布局。所有这些新的区域都是私有的、写时复制的。代码和数据区域被映射为hello文件中的.text和.data区。bss区域时哀求二进制0的,映射到匿名文件,其巨细包括在hello中。栈和堆区域也是哀求二进制0的,初始长度为0.
3.映射共享区域。如果hello步伐域共享对象链接,比如C标准库libc.so,那么这些对象都是动态链接到这个步伐的,然后再映射到用户假造地址空间中的共享区域内。
4.设置步伐计数器(PC)。execve做的最后一件事情就是设置当前进程上下文中的步伐计数器,使之指向代码区域的入口点。
7.8 缺页故障与缺页停止处置惩罚
情况1:段错误:首先,先判断这个缺页的假造地址是否合法,那么遍历所有的合法区域布局,如果这个假造地址对所有的区域布局都无法匹配,那么就返回一个段错误(segment fault)
情况2:非法访问:接着查看这个地址的权限,判断一下进程是否有读写改这个地址的权限。
情况3:如果不是上面两种情况那就是正常缺页,那就选择一个页面捐躯然后换入新的页面并更新到页表。
7.9动态存储分配管理
动态内存分配器维护着一个进程的假造内存区域,称为堆。堆是一个哀求二进制零的区域,它紧接在未初始化的数据区域后开始,并向上生长。对于每个进程,内核维护着一个变量brk,指向堆的顶部。
分配器有两种风格,但是这两种风格都要求应用显示的分配块。
其中显示分配器要求显示开释任何已分配的块,如malloc、new等。
隐式分配器要求分配器检测一个已分配块何时不再被步伐所利用,那么就开释这个块。所以也叫垃圾收集器。
显示分配器有以下几点要求:能够处置惩罚恣意哀求序列;立即相应哀求;只是用堆;对齐开;不修改已分配的块。
在性能上有两点寻求:
1.最大化吞吐率;
2.最大化内存利用率;
但是这两点通常是对立的。
详细的技术有以下:隐式空闲列表和显式空闲链表
图表 61:隐式空闲列表和显式空闲链表
7.10本章小结
本章是理解盘算机体系存储的重中之重,从内存的分页式管理,到三级cache的高层内存管理,再到一个步伐内部的堆的管理。其中的头脑十分复杂,却又十分精巧。
我们重要先容了储存器的地址空间,讲述了假造地址、物理地址、线性地址、逻辑地址的概念,尚有进程fork和execve时的内存映射的内容。形貌了体系如何应对那些缺页异常,最后形貌了malloc的内存分配管理机制,操作体系为了稳固的运行,不辞劳怨,精妙的安排了内存的空间,既要分配内存,又要回收内存。
(第7章 2分)
第8章 hello的IO管理
8.1 Linux的IO装备管理方法
装备的模型化:文件
文件的范例:
普通文件(regular file):包罗恣意数据的文件。
目次(directory):包罗一组链接的文件,每个链接都将一个文件名映射到一个文件(他尚有另一个名字叫做“文件夹”)。
套接字(socket):用来与另一个进程进行跨网络通信的文件
命名通道
符号链接
字符和块装备
装备管理:unix io接口
打开和关闭文件
读取和写入文件
改变当前文件的位置
装备的模型化:文件
装备管理:unix io接口
8.2 简述Unix IO接口及其函数
int open(char * filename, int flags, mode_t mode);
若打开文件成功则返回文件形貌符,否则返回-1。
flags有多种O_RDONLY(只读)、O_WRONLY(只写)、O_RDWR(可读可写)、O_CREAT(如果文件不存在,就创建它的一个截断的空文件)、O_TRUNC(如果文件已经存在,就截断它)、O_APPEND(在每次写操作前,设置文件位置到文件的末端处)。
mode参数指定访问权限位。
int close(int fd);
会关闭一个打开的文件,如果关闭一个已关闭的文件形貌符会出错。
ssize_t read(int fd, void *buf, size_t n);
若成功则返回读的字节数,若EOF则为0,若出错则为-1。
ssize_t write(int fd, const void *buf, size_t n);
若成功则返回为写的字符数,若出错则返回-1。
read函数从形貌符为fd的当前位置复制最多n个字节到内存位置buf。返回值-1表现一个错误,而返回值0表现EOF。否则,返回值表现的是现实传送的字节数量。
write函数从内存位置buf复制至多n个字节到形貌符fd的当前文件位置。可以通过调用lseek函数,显示地修改当前文件的位置。
8.3 printf的实现分析
Printf的运行过程:
从vsprintf生成显示信息,显示信息传送到write体系函数,write函数再陷阱-体系调用 int 0x80或syscall.字符显示驱动子步伐。从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。显示芯片按照革新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。
printf必要做的事情是:接受一个fmt的格式,然后将匹配到的参数按照fmt格式输出。
图表62 :print格式
上面是printf的代码,我们可以发现,他调用了两个外部函数,一个是vsprintf,尚有一个是write
从vsprintf生成显示信息,到write体系函数,到陷阱-体系调用 int 0x80或syscall等.
字符显示驱动子步伐:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。
显示芯片按照革新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。
8.4 getchar的实现分析
int getchar(void)
{
static char buf[BUFSIZ];
static char* bb=buf;
static int n=0;
if(n==0)
{
n=read(0,buf,BUFSIZ);
bb=buf;
}
return (–n>=0)?(unsigned char)*bb++:EOF;
}
异步异常-键盘停止的处置惩罚:键盘停止处置惩罚子步伐。接受按键扫描码转成ascii码,保存到体系的键盘缓冲区。
getchar等调用read体系函数,通过体系调用读取按键ascii码,直到接受到回车键才返回。
8.5本章小结
本章扼要总结I/O的有关知识,通过对外部装备的模型化实现简单、贯通的读写操作,将所有的IO装备看作文件,通过简单的几个体系函数的组合就完成了各种的读写操作。同时还提供了一种树布局的文件管理模式,而且把目次也抽象为了一种文件。
必要我们重点在编程中把握read、write、lseek、open、close等根本函数,深入理解内部机制,做到安全的对文件进行读写。
(第8章1分)
结论
用盘算机体系的语言,逐条总结hello所经历的过程。
你对盘算机体系的设计与实现的深切感悟,你的创新理念,如新的设计与实现方法。
Hello的一生就此终结了,让我们用盘算机体系的语言回顾hello的一生吧
- 预处置惩罚,把C原始文件变成预处置惩罚文件
- 编译,编译成汇编语言
- 汇编,汇编语言转成二进制hello.o
- 链接,把外部库链接到hello.o上,而且进行重定位等一系列操作,最后成为了可执行文件
- Shell fork 出子进程,用execve对可执行文件进行加载
- 发送信号,进行信号处置惩罚
- 最后终止步伐并回收
用形象的语言说,懵懂的,刚编写步伐的入门菜鸟,编写了一个hello.c步伐。但是我们的语言对于盘算机来说太难懂了,他实验翻译,终于编译成了汇编语言,但是他还是读不懂详细的处置惩罚信息和地址,所以他又实验翻译成了二进制语言。二进制语言他读懂了,但是发现里面有许多本身其他的知识,于是盘算机把许多的库链接到我们的步伐上。他实验fork出本身的一部门精神处置惩罚hello,但是我们又脸滚键盘,发了一堆的信号,我们的步伐和shell只能困难的阻塞,处置惩罚各种信号。终于,我们按了CtrlC,我们的hello终于可以被终止了,然后尸体被回收,我们的盘算机也终于可以苏息了(大概说处置惩罚其他进程了)。
在学习后,我发现盘算机体系是十分精妙的体系,充满了人类的智慧,他把一个复杂的事物分别成简单的步骤,一步步进行处置惩罚。而且进行了公道的调度安排,让进程有条不紊的进行。这也启发了我的步伐设计与日常生存,我们不妨把本身的生存看成一个体系,按照步骤预处置惩罚,汇编本身的生存,面对各种信号有条不紊的处置惩罚屏蔽等等。至于盘算机体系,我们可以实验打破如今的架构,比如让指令和数据隔离,亦大概硬件级并行的架构,都是未来大概的创新点。
Hello,代表步伐员对于步伐天下的第一声呼唤,但是,他的编程之路,他的步伐人生,才刚刚开始
(结论0分,缺失 -1分,根据内容酌情加分)
附件
hello.i 预处置惩罚之后文本文件
hello.s 编译之后的汇编文件
hello.o 汇编之后的可重定位目标步伐
hello 链接之后的可执行目标文件
hello.elf Hello.o 的 ELF 格式
(附件0分,缺失 -1分)
参考文献
为完本钱次大作业你翻阅的书籍与网站等
[1] 林来兴. 空间控制技术[M]. 北京:中国宇航出版社,1992:25-42.
[2] 辛希孟. 信息技术与信息服务国际研讨会论文集:A集[C]. 北京:中国科学出版社,1999.
[3] 赵耀东. 新时代的工业工程师[M/OL]. 台北:天下文化出版社,1998 [1998-09-26]. http://www.ie.nthu.edu.tw/info/ie.newie.htm(Big5).
[4] 谌颖. 空间交会控制理论与方法研究[D]. 哈尔滨:哈尔滨工业大学,1992:8-13.
[5] KANAMORI H. Shaking Without Quaking[J]. Science,1998,279(5359):2063-2064.
[6] CHRISTINE M. Plant Physiology: Plant Biology in the Genome Era[J/OL]. Science,1998,281:331-332[1998-09-23]. http://www.sciencemag.org/cgi/ collection/anatmorp.
(参考文献0分,缺失 -1分)
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |