本文主要是介绍CSAPP HIT 大作业 HelloP2P,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
计算机系统
大作业
题 目 程序人生-Hello’s P2P
专 业 计算机类
学 号 L190201402
班 级 1903007
学 生 李珢知
指 导 教 师 吴锐
计算机科学与技术学院
2021年5月
关键词: 对计算机系统的深刻理解; hello world; 程序的生命周期
本文主要由hello程序叙述Linux系统的生平周期, 研究hello过程 完成的所有过程从处理、编译、汇编、链接、流程管理、内存管理和I/O管理几个方面分析Hello过程中出现的各种现象,理解电脑的各种行为。另外,结合教科书的知识,详细说明我们的计算机系统是如何对hello进行流程管理、存储管理、I/O管理的,通过对hello生命周期的探索,我们对计算机系统有了更多的了解。 努力把课本知识和实践结合起来,达到连贯性效果。
(摘要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是Program to process过程。 program 是执行任务的命令 。 为创建可执行程序, 需要经过 cpp 预处理、 ccl 编译、 as 汇编和 ld 链接的步骤 。 Process是执行模块, hello.c转换为Hello, 实现process。
"020(zero to zero)是将程序从无到有,最终再到无的所有过程。 在应用程序中 shell 接收命令, fork 函数生成子进程 。 下级进程在进程结束后由上级进程循环利用。
1.2 环境与工具
图1.2.1
硬件环境 : Intel Core i5-8265Ux64 CPU@ 1.60GHz, RAM 16GB DDR
软件环境 : VMware 16, Ubuntu 20.04
开发与调式工具 : vim, gcc, as, ld, edb, readelf, HexEdit
1.3 中间结果
文件名称 | 文件作用 |
hello.i | 预处理之后文本文件 |
hello.s | 编译之后的汇编文件 |
hello.o | 汇编之后的可重定位目标执行 |
hello | 链接之后的可执行目标文件 |
hello2.c | 测试程序代码 |
hello2 | 测试程序 |
helloo.objdmp | Hello.o的反汇编代码 |
helloo.elf | Hello.o的ELF格式 |
hello.objdmp | Hello的反汇编代码 |
hello.elf | Hellode ELF格式 |
tmp.txt | 存放临时数据 |
表1.3.1 文件名和作用
1.4 本章小结
本章主要介绍hello的p2p, 020过程, 并提示为写这篇论文而生成的中间结果文件的名字, 文件的作用等有关此次实验的信息。
(第1章0.5分)
第2章 预处理
2.1 预处理的概念与作用
(以下格式自行编排,编辑时删除)
2.1 前处理的概念及作用
前处理是编译前执行的处理。 事前处理有三个主要方面。
1.宏定义
2.包含文件
3.条件编译
宏定义: 定义特定内容的标识符 。 前处理将源代码中显示的标识符替换为宏观上定义的值 。 宏观可定义为表示值或类似函数的全球符号。
包含文件 : # include 前处理指示器根据指示扩展包含的文件 。
条件编译:有条件的编译指南用于确定是否是编译过的代码。
前处理器( cpp) 根据字符 # 开头的命令修改原来的 C 程序 。 例如 , # include 命令指示前处理器读取系统头文件 stdio 。 他的内容直接插入到程序文本中。 这将创建另一个 C 应用程序, 用于作为文件扩展名 。
2.2在Ubuntu下预处理的命令
命令: gcc hello.c –E –o hello.i
图2.2.1
2.3 Hello的预处理结果解析
打开hello.i文件,可以发现整个文件已经被扩展成了3060行。
图2.3.1
图2.3.2
2.4 本章小结
本章介绍了根据Ubuntu的GCC方针的前处理概念、作用及前处理方法,并说明hello.c和hello.i的前处理阶段是如何处理的。
(第2章0.5分)
第3章 编译
3.1 编译的概念与作用
概念 :
编译是指从字典处理文本文件到编译文本文件生成文本的进程 。 这里主要包括词汇分析、语法分析、意义检查、中间代码生成、目标代码生成五个阶段。
作用: 编译作用主要是将文本文件 hello.i 转换为文本文件 hello.s, 并在出现语文错误时提供信息, 运行流程主要分析为三个阶段( 词汇分析 , 语法分析 , 生成目标代码 )。
1) 词汇分析:词汇分析的任务是处理由文字组成的单词,从左到右扫描源程序,生成一个单词符号,将源程序转换为字符串。
2) 语法分析: 语法分析器用于输入, 分析单词符号绳是否构成诸如格式、 分配、 循环等语法单位, 最后确认是否构成满足要求的程序, 分析使用该语言的语法规则。 每篇文章的逻辑结构正确吗? 而且节目是最终的语句。
3) 生成目标代码:建议目标代码生成器在词组分析或优化中间代码(可执行的机器语言代码)编译后,使用汇编语言代码。
3.2 在Ubuntu下编译的命令
命令 :gcc –S hello.i –o hello.s
图3.2.1
3.3 Hello的编译结果解析
3.3.0 编译文件指令
图 3.3.1
指令 | 作用 |
.file | 声明源文件 |
.text | 声明代码段 |
.data | 声明数据段 |
.align | 声明对指令或数据存放地址进行对齐的方式 |
.type | 指令类型 |
.size | 声明大小 |
.section .rodata | 只读数据,rodata节 |
.globl | 全局变量 |
表3.3.1
3.3.1数据
1.字符串
程序中有两个字符串,由上图可知,这两个字符串都在只读数据段中,分别如图所示:
图3.3.1.1
这两个字符串作为printf函数的参数:
2.局部变量i
main函数声明了一个局部变量i,编译器进行编译的时候将局部变量i会放在堆栈中。如图所示,局部变量i放在栈上-4(%rbp)的位置。
图3.3.1.2
3.main函数
参数 argc 作为用户传给main的参数。也是被放到了堆栈中。
4.各种立即数
hello.c中唯一的数组是作为main函数的第二个参数,数组的每个元素都是一个指向字符类型的指针。数组的起始地址存放在栈中-32(%rbp)的位置,被两次调用找参数传给printf
图3.3.1.3
3.3.2.全局函数
由hello.c可知,hello.c声明了一个全局函数int main(int argc,char *argv[]),经过编译之后,main函数中使用的字符串常量也被存放在数据区。
3.3.3赋值操作
程序中的赋值操作主要有:i=0这条赋值操作在汇编代码主要使用mov指令来实现,而根据数据的类型又有好几种不一样的后缀
movb:一个字节
movw:两个字节
movl:四个字节
movq:八个字节
3.3.4 算数操作
hello.c中的算数操作有:i++,由于是i是int类型的,因此汇编代码只用addl就能实现其他的操作有
指令 | 效果 |
leaq S,D | D=&S |
INC D | D+=1 |
DEC D | D-=1 |
NEG D | D=-D |
ADD S,D | D=D+S |
SUB S,D | D=D-S |
3.3.5 关系操作
(1) argc!=3;是在一条件语句中的条件判断:argc!=3,进行编译时,这条指令被编译为:cmpl $3,-20(%rbp),同时这条cmpl的指令还有设置条件码的作用,当根据条件码来判断是否需要跳转到分支中。
图3.3.5.1
(2)i<8,在hello.c作为判断循环条件,在汇编代码被编译为:cmpl $7,-4(%rbp),计算 i-7然后设置 条件码,为下一步 jle 利用条件码进行跳转做准备。
图3.3.5.2
3.3.6 控制转移指令
汇编语言中首先设置条件码,然后根据条件码来进行控制转移,在hello.c中,有以下控制转移指令:
(1)判断i是否为3,如果i等于3,则不执行if语句,否则执行if语句,对应的汇编代码为
图3.3.6.1
(2)for(i=0;i<8;i++),通过每次判断i是否满足小于8来判断是否需要跳转至循环语句中,对应的汇编代码为
图3.3.6.2
第一个红色方框:首先i赋初值0,然后无条件跳转至判断条件的代码中,即.L3.
第二个红色方框:判断i是否符合循环的条件,符合直接跳转至.L4,也就是循环体的内部
3.3.7函数操作
调用函数时有以下操作:(假设函数P调用函数Q)
(1)传递控制:进行过程 Q 的时候,程序计数器必须设置为 Q 的代码的起始 地址,然后在返回时,要把程序计数器设置为 P 中调用 Q 后面那条指令的 地址。
(2)传递数据:P 必须能够向 Q 提供一个或多个参数,Q 必须能够向 P 中返回 一个值。
(3) 分配和释放内存:在开始时,Q 可能需要为局部变量分配空间,而在返回 前,又必须释放这些空间。
hello.C涉及的函数操作有:
main函数,printf,exit,sleep ,getchar函数
main函数的参数是argc和argv;两次printf函数的参数恰好是那两个字符串
exit参数是1,sleep函数参数是atoi(argv[3])
函数的返回值存储在%eax寄存器中。
3.3.8类型转换
hello.c中涉及的类型转换是:atoi(argv[3]),将字符串类型转换为整数类型其他的类型转换还有int、float、double、short、char之间的转换
3.4 本章小结
本章主要用汇编语言指示语、 数据类型、 汇编语言作业、 控制传输、 函数作业和类型转换等文本文件hello.s的特定操作来描述预先进程文本文件。
(以下格式自行编排,编辑时删除)
(第3章2分)
第4章 汇编
4.1 汇编的概念与作用
概念: 把汇编语言翻译成机器语言的过程叫做编译。
作用:汇编程序(AS)把hello转换成机器语言指令,将这些指令打包成一种叫做可伸缩目标程序的格式,并将结果保存到二进制目标文件Hello.o.。
4.2 在Ubuntu下汇编的命令
指令:gcc hello.s –c –o hello.o
图4.2.1
4.3 可重定位目标elf格式
(1) ELF Header:用命令:readelf -h hello.o,
ELF Header:以 16B 的序列 Magic 开始,Magic 描述了生成该文件的系统 的字的大小和字节顺序,ELF 头剩下的部分包含帮助链接器语法分析和解 ## 标题释目标文件的信息,其中包括 ELF 头的大小、目标文件的类型、机器类型、 字节头部表(section header table)的文件偏移,以及节头部表中条目的大 小和数量等信息。
图4.3.1
(2) Section Headers:命令:readelf -S hello.o
Section Headers:节头部表,包含了文件中出现的各个节的语义,包括节 的类型、位置和大小等信息。 由于是可重定位目标文件,所以每个节都从0开始,用于重定位。在文件头中得到节头表的信息,然后再使用节头表中的字节偏移信息得到各节在文件中的起始位置,以及各节所占空间的大小,同时可以观察到,代码是可执行的,但是不能写;数据段和只读数据段都不可执行,而且只读数据段也不可写。
图4.3.2
(3)查看符号表.symtab :命令readelf -s hello.o
.symtab: 存放程序中定义和引用的函数和全局变量的信息。name是符号名称,对于可冲定位目标模块,value是符号相对于目标节的起始位置偏移,对于可执行目标文件,该值是一个绝对运行的地址。size是目标的大小,type要么是数据要么是函数。Bind字段表明符号是本地的还是全局的。
图4.3.3
4.4 Hello.o的结果解析
objdump -d -r hello.o 分析hello.o的反汇编,并请与第3章的 hello.s进行对照分析。
图4.4.1, 图4.4.2
通过反汇编的代码和hello.s进行比较,发现汇编语言的指令并没有什么不同的地方,只是反汇编代码所显示的不仅仅是汇编代码,还有机器代码,机器语言程序的是二进制机器指令的集合,是纯粹的二进制数据表示的语言,是电脑可以真正识别的语言。机器指令由操作码和操作数构成,汇编语言是人们比较熟悉的词句直接表述CPU动作形成的语言,是最接近CPU运行原理的语言。每一条汇编语言操作码都可以用机器二进制数据来表示,进而可以将所有的汇编语言(操作码和操作数)和二进制机器语言建立一一映射的关系,因此可以将汇编语言转化为机器语言,通过对机器代码的分析可以看出一下不同的地方。
4.5 本章小结
本章介绍组装过程,从hello.s到hello.o. 这个过程是非常必要的,高级语言机器不懂操作,因此有必要编写高效的机器。 语言被转化成机器效率高的低级语言。与o作比较以便对两者都更深入的理解。
(第4章1分)
第5章 链接
5.1 链接的概念与作用
概念:链接是收集及结合各种代码和数据单元,并结合流程,可活塞到内存上并执行的程序。
作用: 编译时, 即源代码转换为机器代码时, 即当程序被装入存储器运行时, 甚至运行时, 链接也可以被执行。 运行程序 。 在初始计算机系统中手动运行, 在最新系统中, 链接会自动运行 。 使用吊环可分离编译。 在开发进程中, 您无需为组成大规模源文件而组建大规模应用程序, 但您可以将这些模块分割成更小、更好的管理模式, 独立修改和编译这些模块。
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
图5.2.1
5.3 可执行目标文件hello的格式
(1)ELF Header:hello的文件头和hello.o文件头的不同之处如下图标记所示,Type类型为EXEC表明hello是一个可执行目标文件,有27个节
图5.3.1
(2)节头部表Section Headers:Section Headers 对 hello中所有的节信息进行了声明,其 中包括大小 Size 以及在程序中的偏移量 Offset,因此根据 Section Headers 中的信息我们就可以用 HexEdit 定位各个节所占的区间(起始位置,大小)。其中 Address 是程序被载入到虚拟地址的起始地址。
图5.3.2
(3)符号表.dynsym
图5.3.3
(4)符号表.symtab
图5.3.4 图5.3.5
5.4 hello的虚拟地址空间
通过查看edb,看出hello的虚拟地址空间开始于0x401000,结束与0x4012c0,
图5.4.1 图5.4.2
5.5 链接的重定位过程分析
指令: objdump –d –r hello > hello.out
图5.5.1
图5.5.2
图5.5.3
图5.5.4
图5.5.5
节名称 | 描述 |
.init | 程序初始化需要执行的代码 |
.plt | 动态链接-过程接表 |
.dynamic | 存放被ld.so使用的动态连接信息 |
.data | 初始化了的数据 |
.comment | 一串包含编译器的NULL-terminated 字符串 |
.interp | 保存ld.so的路径 |
.note.ABI-tag | Linux下特有的部分 |
.hash | 符号的哈希表 |
.gnu.hash | GNU拓展的符号的哈希表 |
.dynsym | 存放.dynsym节中的符号名称 |
.gnu.version | 符号版本 |
.gnu.version_r | 符号引用版本 |
.rela.dyn | 运行时/动态重定位条目 |
.rela.plt | .plt 节的重定位条目 |
.fini | 当程序正常终止时需要执行的代码 |
5.6 hello的执行流程
(以下格式自行编排,编辑时删除)
使用edb执行hello,说明从加载hello到_start,到call main,以及程序终止的所有过程。请列出其调用与跳转的各个子程序名或程序地址。
5.7 Hello的动态链接分析
动态链接的基本思想是把程序按照模块拆分成各个相对独立部分,在程序运行时才将它们链接在一起形成一个完整的程序,而不是像静态链接一样把所有程序模块都链接成一个单独的可执行文件。虽然动态链接把链接过程推迟到了程序运行时,但是在形成可执行文件时(注意形成可执行文件和执行程序是两个概念),还是需要用到动态链接库。比如我们在形成可执行程序时,发现引用了一个外部的函数,此时会检查动态链接库,发现这个函数名是一个动态链接符号,此时可执行程序就不对这个符号进行重定位,而把这个过程留到装载时再进行。
在调用共享库函数时,编译器没有办法预测这个函数的运行时地址,因为定义它的共享模块在运行时可以加载到任意位置。正常的方法是为该引用生成一条重定位记录,然后动态链接器在程序加载的时候再解析它。GNU编译系统使用延迟绑定(lazybinding),将过程地址的绑定推迟到第一次调用该过程时。
延迟绑定是通过GOT和PLT实现的。GOT是数据段的一部分,而PLT是代码段的一部分。两表内容分别为:
PLT:PLT是一个数组,其中每个条目是16字节代码。PLT[0]是一个特殊条目,它跳转到动态链接器中。每个被可执行程序调用的库函数都有它自己的PLT条目。每个条目都负责调用一个具体的函数。
GOT:GOT是一个数组,其中每个条目是8字节地址。和PLT联合使用时,GOT[O]和GOT[1]包含动态链接器在解析函数地址时会使用的信息。GOT[2]是动态链接器在1d-linux.so模块中的入口点。其余的每个条目对应于一个被调用的函数,其地址需要在运行时被解析。每个条目都有一个相匹配的PLT条目。
图5.7.1
5.8 本章小结
在本章中主要介绍了链接的概念与作用、hello的ELF格式,分析了hello的虚拟地址空间、重定位过程、执行流程、动态链接过程.
链接器在软件开发中扮演着一个关键的角色,因为它们使得分离编译(separate compilation)成为可能.我们不用将一个大型的应用程序组织为一个巨大的源文件,而是可以把它分解为更小、更好管理的模块,可以独立地修改和编译这些模块.当我们改变这些模块中的一个时,只需简单地重新编译它,并重新链接应用,而不必重新编译其他文件.
(以下格式自行编排,编辑时删除)
(第5章1分)
第6章 hello进程管理
6.1 进程的概念与作用
概念:计算机程序需要进行对数据集合进行操作所运行的一次活动
作用:是操作系统的基础,是系统进行资源分配和调度的基本单位
6.2 简述壳Shell-bash的作用与处理流程
shell俗称壳,是一种指"为使用者提供操作界面"的嵌入式软件(也被称为命令解析器)。软件提供了一种允许用户与其他操作系统之间进行通讯的一种方式。这种简单的通讯方式可以以交互方式(从键盘输入,并且用户可以立即地得到命令响应),或者以交互方式shellscript(非交互)的方式允许用户执行。shell(即壳)它是一个简单的命令解释器,它允许系统接收到一个用户的命令,然后自动调用相应的命令执行应用程序。
Shell 的处理流程:shell读取用户从终端使用外部设备输入(通常是键盘输入)的指令。解析所读取的指令,如果这个指令是一个内部指令则立即执行,否则,加载调用一个应用程序为申请的程序创建新的子进程,在子进程的上下文中运行。同时shell还允许接收从键盘读入的外部信号,并根据不同信号的功能进行对应的处理。
6.3 Hello的fork进程创建过程
首先了解进程生成进程 。 上位进程通过调用 FORK 函数生成运行中的新下位进程 。 新建的子进程几乎不会完全与子进程同步 。 子进程包括代码及数据单元、臀部、共享库及用户堆栈,与上游水平虚拟地址空间的复印件相同,但独立。 下级进程还提供与上级进程相同的打开的文件描述符复印件, 因此上级进程可以呼叫 fork 。 子进程允许您读取所有在上级进程中打开的文件 。 上位进程和新生成的下位进程的最大区别是 ID 不同 。
FORK 调用 2 次后, 叉子返回上游进程的下游进程 PID, 叉子返回下游进程中的 0 。 上位进程和下位进程同时运行的独立进程 。 内核可以以任何方式执行逻辑控制流的命令 。
Hello的叉子进程生成流程如下: 系统流程是生成Hello子流程后呼叫waitpid()函数了解Hello子流程,程序流程图表如下。
图6.3.1
6.4 Hello的execve过程
fork功能用于生成进程的副本,Execve用于加载和运行程序。 使用 Execve 是系统调用进程 。 Execve函数在当前进程中删除现有用户区域,生成现有用户区域并执行 hello.out 。 生成新区域结构包含代码、 数据、 臀部和堆栈集 。 共享个体通过动态链接映射到 Hello 运行进程的共享区域,PC 则被设置为指向代码区域进入点。
6.5 Hello的进程执行
进程上下文信息: 上下文是指操作系统跟踪运行进程所需的所有状态信息 。 此状态是内容, 包含PC和寄存器文件的当前值、 主要保存的内容等诸多信息 。
进程时间片断: 进程运行部分控制流的各个时间称为时间片断 。
预定进程: 在运行进程的过程中, 内核可以先运行当前进程, 并重新启动先前预设的进程 。 这个决定叫做预约。
用户模式和内核模式: 内核模式下运行的进程可以在命令集合中执行命令, 并在系统的内存位置存取 。 在用户模式下, 不允许在进程中执行有权限的命令 。 用户模式的进程无法直接参照地址空间内内核区域内的代码和数据 。
图6.5.1
6.6 hello的异常与信号处理
(以下格式自行编排,编辑时删除)
hello执行过程中会出现哪几类异常,会产生哪些信号,又怎么处理的。
程序运行过程中可以按键盘,如不停乱按,包括回车,Ctrl-Z,Ctrl-C等,Ctrl-z后可以运行ps jobs pstree fg kill 等命令,请分别给出各命令及运行结截屏,说明异常与信号的处理。
(1)正常结束
图6.6.1
(2)中途按下ctrl+z,程序挂起,对应的是shell接收到SIGSTP信号
图6.6.2
(3)输入ps指令:可以发现hello进程没有结束
图6.6.3
(4)输入jobs查看hello和jid
图6.6.4
(5)输入fg 1,就可以让hello继续进行,输出还没有输出的内容.
图6.6.5
(6)如果在运行到一半的时候输入ctrl-c,就会发现进程立即结束了
图6.6.6
(7)输入pstree 以树状图显示进程间的关系
图6.6.7, 图6.6.8
6.7本章小结
在本章中,介绍了进程的定义和作用,介绍了Shell的处理流程,介绍了shell如何调用fork创建新进程,如何调用execve执行hello,分析了hello的进程执行,还研究了hello的异常与信号处理.
异常控制流发生在计算机系统的各个层次.在硬件层,硬件检测到的事件会触发控制突然转移到异常处理程序.在操作系统层,内核通过上下文切换将控制从一个用户进程转移到另一个用户进程.在应用层,一个进程可以发送信号到另一个进程,而接收者会将控制突然转移到它的一个信号处理程序.一个程序可以通过回避通常的栈规则,并执行到其他函数中任意位置的非本地跳转来对错误做出反应.
(第6章1分)
第7章 hello的存储管理
7.1 hello的存储器地址空间
逻辑地址空间: 编译后在汇编中显示的程序代码的地址 。 机器语言命令中用于指定被运算者或命令的地址 。
线性地址空间: 逻辑地址在整数地址的顺序集合 — — 即分割机制之后转换为线性地址, 而不是负数。
虚拟地址空间: 不是负数, 而是正数地址的顺序集 — 线性地址空间 。
物理地址空间: 用于指定与处理器和 CPU 连接的地址总线的内存芯片等级单元地址 。
7.2 Intel逻辑地址到线性地址的变换-段式管理
段式管理是指将程序分几个部分存放起来,以便存储。 每个片段都是一个逻辑实体,片段的产生与程序的模块化有直接关系。 段式管理由段表执行,段表包括段式编号或段式名称、段式起点、加载位、段式长度等。 此外,还需要主存占用区域表和主存可用区域表。
段式寄存器用于存储段式选择器。 格式描述符是一个数据结构,它是一个段式表项。 描述符表实际上是一个段式表,它由格式描述符组成。 描述符表包括三种类型:1)全局描述符表GDT,本地描述符表LDT和中断描述符表IDT。
7.3 Hello的线性地址到物理地址的变换-页式管理
将名进程的虑拟空间划分成若干个长度相等的页,页式管理把内存空间按页的大小划分成片或者页面,然后把页式虚拟地址与内存地址建立一一对应页表,并用相应的硬件地址变换机构,来解决离散地址变换问题。页式管理采用请求调页或预调页技术实现了内外存存储器的统一管理。
7.4 TLB与四级页表支持下的VA到PA的变换
虚拟地址被划分成4个VPN和1个VPO。 每个VPNi都是一个到第1级页表的索引, 其中1<=jc=4.第j级 页表中的每个PTE, 1<=j<=3, 都指向第i+1级的某个页表的基址。 第四级页表中的每个PTE包含某 个物理页面的PPN, 或者一个磁盘块的地址。 为了构造物理地址, 在能够确定PPN之前, MMU必 须访问4个PTE。 将得到的PPN和虚拟地址中的VPO串联起来, 就得到相应的物理地址。
7.5 三级Cache支持下的物理内存访问
1. CPU给出VA
2. MMU)用VPN到TLB中找寻PTE, 若命中, 得到PA;
若不命中, 利用VPN (多级页 表机制) 到内存中找到对应的物理页面, 得到PA。
3. PA分成PPN和PPO两部分。
利用其中的 PPO, 将其分成CI和CO, CI作为cache组索引, CO作为块偏移, PPN作为tag。 先访问一级缓存, 不命中时访问二级缓存, 再不命中访问三级缓存, 再不命中访问主存, 如果主存 缺页则访问硬盘
7.6 hello进程fork时的内存映射
当 fork 函数被 shell 进程调用时,内核为新进程创建各种数据结构,并分配给 它一个唯一的 PID,为了给这个新进程创建虚拟内存,它创建了当前进程的 mm_struct、区域结构和页表的原样副本。它将这两个进程的每个页面都标记为只 读,并将两个进程中的每个区域结构都标记为私有的写时复制。
7.7 hello进程execve时的内存映射
execve函数调用驻留在内核区域的启动加载器代码,在当前进程中加载并运行包含在可执行目标文件hello中的程序,用hello程序有效地替代了当前程序.加载并运行hello需要以下几个步骤:
1.删除已存在的用户区域,删除当前进程虚拟地址的用户部分中的已存在的区域结构.
2.映射私有区域,为新程序的代码、数据、bss和栈区域创建新的区域结构,所有这些新的区域都是私有的、写时复制的.代码和数据区域被映射为hello文件中的.text和.data区,bss区域是请求二进制零的,映射到匿名文件,其大小包含在hello中,栈和堆地址也是请求二进制零的,初始长度为零.
3.映射共享区域, hello程序与共享对象libc.so链接,libc.so是动态链接到这个程序中的,然后再映射到用户虚拟地址空间中的共享区域内.
4.设置程序计数器(PC),execve做的最后一件事情就是设置当前进程上下文的程序计数器,使之指向代码区域的入口点.
图7.7.1
7.8 缺页故障与缺页中断处理
(以下格式自行编排,编辑时删除)
7.9动态存储分配管理
(以下格式自行编排,编辑时删除)
Printf会调用malloc,请简述动态内存管理的基本方法与策略。
7.10本章小结
本章具体分析了虚拟内存管理。在地址层面,由逻辑地址开始,首先转为线性地址,再转为虚拟地址,最后转为物理地址,再通过TLB、三级cache等对上述过程进行加速形成了完整的计算机地址翻译。同时,大致了解了动态内存分配的方法与策略。
(第7章 2分)
第8章 hello的IO管理
8.1 Linux的IO设备管理方法
设备建模:文件
设备管理:Unix io接口
接口: 接口是连接CPU和外围设备的组件。 它完成CPU与外部世界之间的信息传输。 也包括辅助CPU的外围电路,如中断控制器、DMA控制器、定时器、高速缓存(cache)
将Linux档案设定为字节序列;
把所有的IO设备建模成文件,甚至内核也映射到文件(内核图像、内核数据结构)。 所有输入和输出都作为相应的文件读和写
8.2 简述Unix IO接口及其函数
1. 打开文件:open(),打开一个已经存在的文件或者创建一个新文件。
2. 关闭文件:close(),关闭一个打开的文件。
3. 读取文件:read(),从当前文件位置复制字节到内存。
4. 写入文件:write(),从内存复制字节到当前文件位置。
5. 改变文件位置:lseek()
8.3 printf的实现分析
图8.3.1
printf程序按照格式fmt结合参数args生成格式化之后的字符串,并返回字串的长度
图8.3.2
vsprintf 返回要打印的字符串长度 。 vsprintf是格式。 确定输出类型的格式字符串fmt 。 如果格式字符串格式化参数, 输出将被格式化 。
最后调用 write 。
图8.3.3
8.4 getchar的实现分析
非同步处理-键盘接口的键盘中断一按键盘,键盘的扫描,扫描仪的要求。键盘上的要求高,扫描后转换成ASCII代码系统中将存储于键盘缓冲。
在系统函数函数getchar,底细,调用read。系统调用通过缓冲区内存储的键盘代码,看过之后,ASCII,热的第一个字读,直到返回,关闭getchar
图8.4.1
8.5本章小结
本章大致说明了linux系统下的I/O管理,包括文件操作函数、printf函数以及getchar函数.
(第8章1分)
结论
Hello 源代码 hello.c. 预先处理和编译, 生成汇编, 通过汇编生成目标文件, 目标文件通过链接器形成可执行文件, 在 Linux 下通过 shell 运行, 与计算机上的其他自主文件同步, 通过异常处理机制运行信号。在运行程序期间,通过Intel Memory管理机制访问逻辑地址、虚拟地址、物理地址,交换数据或通过IO机制交换输入输出。
- 编辑hello.c
- 预处理,得到预处理文件hello.i编辑hello.c
- 通过hello.i编译器处理生成文本文件hello.s
- hello.s变成可重定位文件hello.o(汇编
- 将hello.o与可重定位目标文件动态链接库链接成可执行文件hello(链接)
- 在shell中键入./hello L190201402 liyinzhi
- shell调用fork创建子进程
(结论0分,缺失 -1分,根据内容酌情加分)
附件
列出所有的中间产物的文件名,并予以说明起作用。
(附件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分)
这篇关于CSAPP HIT 大作业 HelloP2P的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!