计算机系统
大作业
题 目 程序人生-Hello’s P2P
专 业 计算机科学与技术
学 号 2021112813
班 级 2103101
学 生 王松
指 导 教 师 刘宏伟
计算机科学与技术学院
2022年5月
摘要是论文内容的高度概括,应具有独立性和自含性,即不阅读论文的全文,就能获得必要的信息。摘要应包括本论文的目的、主要内容、方法、成果及其理论与实际意义。摘要中不宜使用公式、结构式、图表和非公知公用的符号与术语,不标注引用文献编号,同时避免将摘要写成目录式的内容介绍。
关键词:关键词1;关键词2;……;
目 录
2.2在Ubuntu下预处理的命令.......................................................................... - 5 -
3.2 在Ubuntu下编译的命令............................................................................. - 6 -
4.2 在Ubuntu下汇编的命令............................................................................. - 7 -
5.2 在Ubuntu下链接的命令............................................................................. - 8 -
5.3 可执行目标文件hello的格式.................................................................... - 8 -
6.2 简述壳Shell-bash的作用与处理流程..................................................... - 10 -
6.3 Hello的fork进程创建过程..................................................................... - 10 -
6.6 hello的异常与信号处理............................................................................ - 10 -
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 -
8.1 Linux的IO设备管理方法.......................................................................... - 13 -
8.2 简述Unix IO接口及其函数....................................................................... - 13 -
第1章 概述
1.1 Hello简介
P2P: 全称为From Program to Progress,从项程序到进程。这个看似简单的过程需要经过预处理、编译、汇编、链接等一系列的复杂动作才可以生成一个可执行目标文件。在运行时,我们打开Shell,等待我们输入指令。通过输入./hello,使Shell创建新的进程用来执行hello。 操作系统会使用fork产生子进程,然后通过execve将其加载,不断进行访存、内存申请等操作。最后,在程序结束返回后,由父进程或祖先进程进行回收,程序结束。
020:全称为From 0 to 0,从无到终。Hello的出生是由操作系统进行存储管理、地址翻译、内存访问,通过按需页面调度来开始这段生命。父进程或祖先进程的回收也标志着它生命的结束。
1.2 环境与工具
1.2.1硬件环境
AMD 5800h,X64 CPU; 2GHz; 16G RAM;
1.2.2软件环境
Windows10
Wsl2
Ubuntu22.04
1.2.3开发与调试工具
ClodeBlocks; gedit, gcc;VSCode
1.3 中间结果
hello.c 储存hello程序源代码
hello.i 源代码经过预处理产生的文件
hello.s hello程序对应的汇编语言文件
hello.o 可重定位目标文件
hello_o.s hello.o的反汇编语言文件
hello.elf hello.o的ELF文件
hello 可执行文件
hello.elf 可执行文件的ELF文件格式
hello.s 可执行文件的汇编语言文件
1.4 本章小结
本章对hello进行了一个简介,并对其运行流程进行了一个总体的概括。然后介绍了所有操作的环境与工具,以及描述了中间产生的文件信息。
(第1章0.5分)
第2章 预处理
2.1 预处理的概念与作用
预处理的概念
C语言对源程序处理的四个步骤:预处理、编译、汇编、链接。预处理是在程序源代码被编译之前,由预处理器(Preprocessor)对程序源代码进行的处理。这个过程并不对程序的源代码语法进行解析,但它会把源代码分割或处理成为特定的符号为下一步的编译做准备工作。例如#include、#define、#if,分别可以在正式编译前进行引入外部库文件、进行宏定义、如果后接语句为真则添加#if与#endif之间的代码进行编译。
预处理的作用
1:宏定义(如#define) 2:文件包含(#include) 3:条件编译。(#if、#else、#endif)4.:删除注释
2.2在Ubuntu下预处理的命令
gcc -E hello.c -o hello.i
2.3 Hello的预处理结果解析
经过预处理后,原本几行的代码扩充到了3060行,他的作用是处理了所有的预编译操作,即宏定义、文件包含、条件编译、删除注释;
Hello.i如截图所示
2.4 本章小结
本章主要介绍了hello.c程序预处理方面的内容,包括预处理的概念和作用,以及进行了hello.c文件的预处理和结果展示。预处理作为编译运行的第一步是非常重要的一部分,查看.i文件会让我们更加直观的感受到预处理前后源文件的变化。
(第2章0.5分)
第3章 编译
3.1 编译的概念与作用
编译的概念:
编译是利用编译程序从源语言编写的源程序产生目标程序的过程,也是用编译程序产生目标程序的动作。也就是说编译器会将通过预处理产生的.o文件翻译成一个后缀为.s的汇编语言文件,编译就是从高级程序设计语言到机器能理解的汇编语言的转换过程。
编译的功能:
其实从概念中也可以直接提炼出,编译的功能就是产生汇编语言文件,并交给机器。除此之外,编译器还有一些其他功能,例如语法检查等。
3.2 在Ubuntu下编译的命令
gcc -S hello.i -o hello.s
编译命令如下图,可以看到多了一个hello.s文件
3.3 Hello的编译结果解析
同样,使用Vim文本编辑器打开hello.s文件,乍一看是一堆看不懂的东西,实际这就是汇编代码,接下来将对hello.s中出现的汇编指令进行介绍。
hello.s文件内容
3.3.1工作伪指令
我们阅读hello.s文件,发现第一部分的汇编代码有一部分是以.作为开头的代码段。这些代码段是指导汇编器和连接器工作的伪指令。这段代码对我们来说没有什么意义,通常可以忽略这些代码,但对汇编器和连接器缺是十分重要的。这些指导伪代码的含义如下
.file 声明源文件(此处为hello.c)
.text 声明代码节
.section 文件代码段
.rodata Read-only只读文件
.align 数据指令地址对齐方式(此处为8对齐)
.string 声明字符串(此处声明了LC0和LC1)
.globl 声明全局变量
.type 声明变量类型(此处声明为函数类型)
3.3.2数据格式和寄存器结构
在解析下面的汇编代码之前,我们需要先了解数据存储的格式以及寄存器的存储结构,Intel数据类型令16bytes为字,21bytes为双字,各种数据类型的大小一级寄存器的结构如下:
char 字节 b 1
short 字 w 2
int 双字 l 4
long 四字 q 8
char * 四字 q 8
float 单精度 s 4
double 双精度 l 8
3.3.3数据
立即数:
立即数在汇编代码中的呈现形式最为简单易辨认。即数顾名思义,是直接显式使用的一类数据,在汇编代码中通常以$美元符号作为标识。例如下图中的例子,表示的含义是将立即数0放寄存器%eax中。
寄存器变量:
在汇编代码中,指令后面出现过许许多多的形如%rbp形式的代码声明,其实这些就是寄存器存储的变量,通过特定的寻址方式进行引用。
字符串:
.LC0和.LC1作为两个字符串变量被声明。而在.LC0中出现的\347\224等是因为中文字符没有对应的ASCII码值无法直接显式显示,所以这样的字符方式显示。而且这两个字符串都在.rodata下面,所以是只读数据。随后有两句leaq指令,这个指令为加载有效地址,相当于转移操作。
3.3.4数据传送指令
数据传送指令无疑是整个程序运行过程中使用的最频繁的指令。汇编代码中数据移动使用MOV类,这些指令把数据从源位置复制到目的位置,不做任何变化。MOV类中最常用的有四条指令:movb、movw、movl、movq,这些指令执行相同的操作,区别在于他们所移动的数据大小不同,如下表所示。指令的最后一个限制字符必须和寄存器所对应的数据大小保持一致。如下:
MOV\qquadS,D D←S 传送
movb 传送字节
movw 传送字
movl 传送双字
movq 传送四字
除此之外,还有一些指令会先将数据进行零扩展或者符号扩展之后再进行传送。典型实例就是MOVZ(零扩展)和MOVS(符号扩展),因为比价少见并且在hello.s中么有相应的体现,就不展开说明了。
压入数据使用指令pushq,弹出数据使用指令popq,他理解起来其实可以看做一个由两句指令组成的结合体。我们拿popq指令作为例子来说明。
popq %rax 等价于 addq $8 %rsp + movq %rbp, (%rsp)
指令 效果 描述
pushq S R[%rsp]←R[%rsp] - 8;
M[R[%rsp]]←S 将四字压入栈
popq D D←M[R[%rsp]];
R[%rsp]←R[%rsp] + 8 将四字弹出栈
3.3.6算术操作
算术运算也是十分常用的一些指令类,同样的,每种算术运算指令的末尾也有b、w、l、q(例如addb)来限制数据的大小。
指令 效果 描述
INC D
DEC D
NEG D
NOT D D←D + 1
D←D - 1
D← -D
D← ~D 加1
减1
取负
取补
ADD S, D
SUB S, D
IMUL S, D D←D + S
D←D - S
D←D * S 加
减
乘
addq $16, %rax ##加法操作
1
3.3.7逻辑操作
逻辑操作常见的有两类,一类是加载有效地址,一类是位移操作。加载有效地址指令类似于MOV类指令,它的作用是将有效地址写入到目的操作数,相当于C语言中大家所熟知的取址操作,可以为以后的内存引用产生指针。位移操作顾名思义就是将二进制数进行整体左移或者右移。
leaq .LC1(%rip), %rdi ##加载有效地址
1
3.3.8条件控制
汇编语言中,一些指令会改变条件码,例如cmpl指令和setl指令。这种指令一般不会单独使用,会根据比较结果进行后续操作。
cmpl $4, -20(%rbp) ##比较,设置条件码
1
3.3.9跳转语句
跳转指令会根据条件码当前的值来进行相应的跳转。比较常见的是直接跳转,在hello.s中也有体现,如下图所示。cmpl指令判断寄存器中的值和立即数4的大小关系,设置条件码,再进行je。je的含义是jump if equal,也就是说,如果此时的条件码所表示含义为相等,则会跳转到相应的.L2指令行。因此,跳转指令用来实现条件分支。
3.3.10函数调用
call指令用来进行函数的调用。如下图所示的示例,call调用了getchar函数。它会先将函数的返回地址压入运行时栈中,之后跳转到相应的函数代码段进行执行。执行结束通过ret指令返回。如图:
3.4 本章小结
本章对汇编指令做了以下简单的介绍,以及查看了Hello的机器级实现。经过简单的思考,我们便可以发现这些汇编指令和C语言代码语句之间的对应关系。同时,根据一个程序的汇编代码我们也可以翻译出相应的C语言程序的大致样貌。
(第3章2分)
第4章 汇编
4.1 汇编的概念与作用
汇编的概念: 汇编程序是指把汇编语言书写的程序翻译成与之等价的机器语言程序的翻译程序。汇编程序输入的是用汇编语言书写的源程序,输出的是用机器语言表示的目标程序。也就是说,汇编器会把输入的汇编指令文件重新打包成可重定位目标文件,并将结果保存成.o文件。它是一个二进制文件,包含程序的指令编码。
汇编的作用: 它的作用也很明晰了,就是完成从汇编语言文件到可重定位目标文件的转化过程。
4.2 在Ubuntu下汇编的命令
Gcc -C hello.s -o hello.o
4.3 可重定位目标elf格式
4.3.1ELF头
.o文件为目标文件,相当于Windows中的.obj后缀文件,因此直接使用Vim或者其他文本编辑器查看会出现一大堆乱码。那么我们选择查看可重定位目标文件的elf形式,使用命令readelf -h hello.o查看ELF头,结果如下
图2 ELF头信息
ELF头以一个16字节的序列(Magic,魔数)开始,这个序列描述了生成文件的系统的字的大小和字节顺序。ELF头剩下部分的信息包含帮助连接器语法分析和解释目标文件的信息。其中包括ELF头的大小、目标文件的类型和机器类型等。例如上图中,Data表示了系统采用小端法,文件类型Type为REL(可重定位文件),节头数量Number of section headers为13个等信息。
4.3.2Section头
使用命令readelf -S hello.o查看节头,结果如下
图3 Section头信息
夹在ELF头和节头部表之间的都为节,包含了文件中出现的各个节的语义,包括节的类型、位置和大小等信息。各部分含义如下:
名称 包含内容含义
.text 已编译程序的机器代码
.rodata 只读数据
.data 已初始化的全局和静态C变量
.bss 未初始化的全局和静态C变量,以及所有被初始化为0的全局或静态变量
.symtab 一个符号表,存放一些在程序中定义和引用的函数和全局变量的信息
.rel.text 一个.tex节中位置的列表
.rel.data 被模块引用或定义的所有全局变量的重定位信息
.debug 一个调试符号表
.line 原始C源程序中的行号和.text节中机器指令之间的映射
.strtab 一个字符串表(包括.symtab和.debug节中的符号表)
4.3.3符号表
使用命令readelf -s hello.o查看符号表,结果如下
这其中,Num为某个符号的编号,Name是符号的名称。Size表示他是一个位于.text节中偏移量为0处的146字节函数。Bind表示这个符号是本地的还是全局的,由上图可知main函数名称这个符号变量是本地的。
4.3.4可重定位段信息
使用readelf -r hello.o查看可重定位段信息,结果如下
offset是需要被修改的引用的节偏移,Sym.标识被修改引用应该指向的符号。Type告知连接器如何修改新的引用,Addend是一个有符号常数,一些类型的重定位要使用它对被修改的引用的值做偏移调整。
4.4 Hello.o的结果解析
使用objdumo -d -r hello.o命令对hello.o可重定位文件进行反汇编,得到的反汇编结果如下图
看到hello.o的反汇编文件我们很是熟悉,它使用的汇编代码和hello.s汇编文件的汇编代码是一样的,但是在这反汇编文件的字里行间中,也混杂着一些我们相对陌生的面孔,也就是机器代码。
这些机器代码是二进制机器指令的集合,每一条机器代码都对应一条机器指令,到这儿才是机器真正能识别的语言。每一条汇编语言都可以用机器二进制数据来表示,汇编语言中的操作码和操作数以一种相当于映射的方式和机器语言进行对应,从而让机器能够真正理解代码的含义并且执行相应的功能。机器代码与汇编代码不同的地方在于:
分支跳转方面:汇编语言中的分支跳转语句使用的是标识符(例如je .L2)来决定跳转到哪里,而机器语言中经过翻译则直接使用对应的地址来实现跳转。
函数调用方面:在汇编语言.s文件中,函数调用直接写上函数名。而在.o反汇编文件中,call目标地址是当前指令的下一条指令地址。这是因为hello.c中调用的函数都是共享库中的函数,需要等待链接之后才能确定响应函数的地址。因此,机器语言中,对于这种不确定地址的调用,会先将下一条指令的相对地址设置为0,然后再.rela.text节中为其添加重定位条目,等待链接时确定地址。
4.5 本章小结
本章介绍了Hello从hello.s到hello.o的过程。这一节中对hello.o的ELF头,Section头以及符号表进行了分析,可以看到Hello的跟深处的信息。本节还对hello.o的反汇编文件进行了解析,比较了相对于hello.s文件.o文件是怎么让机器更加理解的。
(第4章1分)
第5章 链接
5.1 链接的概念与作用
链接的概念:链接是将各种代码和数据片段收集并组合成为一个单一文件的过程,这个文件可被加载到内存并执行。
链接的作用:将程序从.o文件转化为可执行文件。使分离编译成为可能。
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.3 可执行目标文件hello的格式
分析hello的ELF格式,用readelf等列出其各段的基本信息,包括各段的起始地址,大小等信息。
Elf头:
ELF Header在编译后与原来的汇编后的表的格式是一模一样的,仍然以一个16字节大小的Magic头开始,给出了操作系统和编译器辨别此文件为ELF二进制库,但是会发现type从REL变为EXEC,节点数量变为27个
节头部表:
Linkhello.elf中的节头包含了文件中出现的各个节的语义,包括节的类型、位置、偏移量和大小等信息。与hello.elf相比,其在链接之后的内容更加丰富详细
重定位表:
重定位表中保存着定位、重定位程序中符号定义和引用的信息,所有重定位需要引用的符号都在其中声明
符号表:
符号表存放程序中定义的函数和局部变量的信息
1.Name:符号名称2.Value:符号相对于目标节起始位置偏移3.Size:目标的大小4.Type:类型,全局变量或函数5.Bind:表明是本地的还是全局的
5.4 hello的虚拟地址空间
使用edb加载hello,查看本进程的虚拟地址空间各段信息,并与5.3对照分析说明。
使用edb打开hello可执行文件,可以在edb的Data Dump窗口看到hello的虚拟地址空间分配的情况,具体内容截图如下:
可通过Symbols Viewer查看具体节点位置
5.5 链接的重定位过程分析
执行命令,bjdump -d -r hello > obj_hello.s
打开obj_hello.s,观察其与hello.o的差异
链接(linking)是将各种代码块组合成一个可被载入内存并执行的文件的过程。链接过程可以在编译时(compile time)进行,此时源代码已经被翻译成了机器指令;也可以在载入时(load time)进行,此时程序已经被加载入了内存并且被加载器(loader)执行;也可以在运行时(run time)进行,此时链接过程是由应用程序进行的。在早期的操作系统中,链接过程需要手动完成,而在现在的系统中,链接过程是由称为链接器(linker)的程序完成的。链接器在软件的发展中起到了很重要的作用,因为它允许独立编译(separate compilation)。现在我们可以将一个大程序分解为较小的且更便于管理的小模块。我们对这些模块进行单独的修改和编译,而不是将整个程序编写为一个大的源文件。当我们改变这些小模块后,只需要将改变的部分简单的进行重新编译链接,而不需要重新编译其他文件。为了生成可执行文件,静态链接器必须执行如下的动作:
符号解析(symbol resolution):在目标文件中我们定义并引用了符号(symbol)。符号解析的目的是将每个符号引用和具体的符号定义结合在一起。
重定位(relocation):编译器和汇编器会从地址0开始生成数据section和代码section。链接器通过将具体的内存地址和每个定义的符号结合在一起来重定位这些section。接下来链接器会修改所有指向这些符号的引用,使得这些引用指向分配的内存地址。
那么结合一下hello.o与obj_hello.s的差异看看链接是如何完成的;
1)链接增加新的函数:
在hello中链接加入了在hello.c中用到的库函数,如exit、printf、sleep、getchar等函数。
2)增加的节:
hello中增加了.init和.plt节,和一些节中定义的函数。
3)函数调用:
hello中无hello.o中的重定位条目,并且跳转和函数调用的地址在hello中都变成了虚拟内存地址。对于hello.o的反汇编代码,函数只有在链接之后才能确定运行执行的地址,因此在.rela.text节中为其添加了重定位条目。
4)地址访问:
hello.o中的相对偏移地址变成了hello中的虚拟内存地址。而hello.o文件中对于某些地址的定位是不明确的,其地址也是在运行时确定的,因此访问也需要重定位,在汇编成机器语言时,将操作数全部置为0,并且添加重定位条目。
我们得出链接实际上是通过链接器将各个.o文件串联在一起,组装成一个新文件的过程
5.6 hello的执行流程
使用edb执行hello,说明从加载hello到_start,到call main,以及程序终止的所有过程。请列出其调用与跳转的各个子程序名或程序地址。
5.7 Hello的动态链接分析
对于动态共享链接库中PIC函数,编译器没有办法预测函数的运行时地址,所以需要添加重定位记录,等待动态链接器处理,为避免运行时修改调用模块的代码段,链接器采用延迟绑定的策略。动态链接器使用过程链接表plt+全局偏移量表got实现函数的动态链接,got中存放函数目标地址,plt使用got中地址跳转到目标函数。
5.8 本章小结
本章介绍了链接的概念和作用,对链接后生成的可执行文件hello的elf格式文件进行了分析,分析了hello的重定位过程、执行过程、动态链接分析的各种处理操作。
(第5章1分)
第6章 hello进程管理
6.1 进程的概念与作用
6.1 进程的概念与作用
6.1.1进程的概念
相较于程序,进程是动态的概念,比如gcc -o pro生成的这个pro文件,当他运行起来以后,系统中就会多一个进程。进程是一个正在运行的程序的实例,系统中的每一个程序都运行在某个进程的上下文中。
6.1.2进程的作用
给应用程序提供两个关键抽象:
一个独立的逻辑控制流,提供一个假象,好像程序独占地使用处理器
一个私有地址空间,提供一个假象,好像程序独占地使用内存系统
6.2 简述壳Shell-bash的作用与处理流程
6.2.1:Shell-bash的作用
Shell-bash的基本作用是一个交互型应用级程序,代表用户运行其他程序,接收用户输入的命令并把它送入内核去执行。它交互性地解释和执行用户输入的命令,能够通过调用系统级的函数或功能执行程序、建立文件、进行并行操作等。包括历史、别名、快捷键、输入输出、执行顺序、管道符。
6.2.2:Shell-bash的处理流程
1.终端进程读取用户由键盘输入的命令行。
2.分析命令行字符串,获取命令行参数,并构造传递给execve的argv向量
3.检查第一个命令行参数是否是一个内置的shell命令
4.如果不是内部命令,调用fork()创建新进程/子进程
5.在子进程中,用步骤2获取的参数,调用execve()执行指定程序。
6.如果用户没要求后台运行(命令末尾没有&号)否则shell使用waitpid等待作业终止后返回。
7.如果用户要求后台运行(如果命令末尾有&号),则shell返回;
6.3 Hello的fork进程创建过程
终端程序通过调用fork()函数创建一个子进程,子进程与父进程几乎完全相同且并发独立运行,子进程执行期间父进程等待子进程完成。
fork进程的创建过程如下:首先,带参执行当前目录下的可执行文件hello,父进程会通过fork函数创建一个新的运行的子进程hello。子进程获取了与父进程的上下文,包括栈、通用寄存器、程序计数器,环境变量和打开的文件相同的一份副本。子进程与父进程的最大区别是有着跟父进程不一样的PID,子进程可以读取父进程打开的任何文件。当子进程运行结束时,父进程如果仍然存在,则执行对子进程的回收,否则就由init进程回收子进程。
6.4 Hello的execve过程
调用函数fork创建新的子进程之后,子进程会调用execve函数,在当前进程的上下文中加载并运行一个新程序hello。execve 函数从不返回,它将删除该进程的代码和地址空间内的内容并将其初始化,然后通过跳转到程序的第一条指令或入口点来运行该程序。将私有的区域映射进来,例如打开的文件,代码、数据段,然后将公共的区域映射进来。后面加载器跳转到程序的入口点,即设置PC指向_start 地址。_start函数最终调用hello中的 main 函数,这样,便完成了在子进程中的加载。
6.5 Hello的进程执行
一系列程序计数器 PC 的值的序列叫做逻辑控制流。由于进程是轮流使用处理器的,同一个处理器每个进程执行它的流的一部分后被抢占,然后轮到其他进程。处理器使用一个寄存器提供两种模式的区分。用户模式的进程不允许执行特殊指令,不允许直接引用地址空间中内核区的代码和数据;内核模式进程可以执行指令集中的任何命令,并且可以访问系统中的任何内存位置。上下文就是内核重新启动一个被抢占的进程所需要恢复的原来的状态,由寄存器、程序计数器、用户栈、内核栈和内核数据结构等对象的值构成。为了能让处理器安全运行,不至于损坏操作系统,必然需要先知应用程序可执行指令所能访问的地址空间范围。因此,就存在了用户态与核心态的划分,核心态可以说是“创世模式”,拥有最高的访问权限,处理器以一个寄存器当做模式位来描述当前进程的特权。进程只有故障、中断或陷入系统调用时才会得到内核访问权限,其他情况下始终处于用户权限之中,保证了系统的安全性。在进程执行的某些时刻,内核可以决定抢占当前进程,并重新开始一个先前被抢占了的进程,这种决策就叫做调度,是由内核中称为调度器的代码处理的。当内核选择一个新的进程运行,我们说内核调度了这个进程。在内核调度了一个新的进程运行了之后,它就抢占了当前进程,并使用上下文切换机制来将控制转移到新的进程。
以执行sleep函数为例,sleep函数请求调用休眠进程,sleep将内核抢占,进入倒计时,当倒计时结束后,hello程序重新抢占内核,继续执行。
当hello调用getchar的时候,实际落脚到执行输入流是stdin的系统调用read,hello之前运行在用户模式,在进行read调用之后陷入内核,内核中的陷阱处理程序请求来自键盘缓冲区的DMA传输,并且安排在完成从键盘缓冲区到内存的数据传输后,中断处理器。此时进入内核模式,内核执行上下文切换,切换到其他进程。当完成键盘缓冲区到内存的数据传输时,引发一个中断信号,此时内核从其他进程进行上下文切换回hello进程。而我们看到的输出结果如下:
6.6 hello的异常与信号处理
异常可以分为四类:中断(interrupt)、陷阱(trap)、故障(fault)和终止(abort),下表对这些类别的属性做了小结
中断:中断是异步发生的,是来自处理器外部的I/O设备的信号的结果。硬件中断不是由任 何一条专门的指令造成的,从这个意义上来说它是异步的。硬件中断的异常处理程序常常 称为中断处理程序(interrupt handler) 。图6.3概述了一个中断的处理
陷阱:陷阱是有意的异常,是执行一条指令的结果。就像中断处理程序一样,陷阱处理程序 将控制返回到下一条指令。陷阱最重要的用途是在用户程序和内核之间提供一个像过程一 样的接口,叫做系统调用。图6.4概述了一个系统调用的处理
故障:故障由错误情况引起,它可能能够被故障处理程序修正。当故障发生时,处理器将控 制转移给故障处理程序。如果处理程序能够修正这个错误情况,它就将控制返回到引起故 障的指令,从而重新执行它。否则,处理程序返回到内核中的abort例程,abort例程会 终止引起故障的应用程序。图6.5概述了一个故障的处理
终止:终止是不可恢复的致命错误造成的结果,通常是一些硬件错误,比如DRAM或者 SRAM位被损坏时发生的奇偶错误。终止处理程序从不将控制返回给应用程序。
6.7本章小结
通过本章的学习,我们了解了进程的概念与作用、体会了壳Shell-bash的作用与处理流程、利用Hello的fork进程学习创建过程、研究了Hello的execve过程、明白了Hello的进程执行以及hello的异常与信号处理
(第6章1分)
第7章 hello的存储管理
7.1 hello的存储器地址空间
(以下格式自行编排,编辑时删除)
结合hello说明逻辑地址、线性地址、虚拟地址、物理地址的概念。
7.2 Intel逻辑地址到线性地址的变换-段式管理
(以下格式自行编排,编辑时删除)
7.3 Hello的线性地址到物理地址的变换-页式管理
(以下格式自行编排,编辑时删除)
7.4 TLB与四级页表支持下的VA到PA的变换
(以下格式自行编排,编辑时删除)
7.5 三级Cache支持下的物理内存访问
(以下格式自行编排,编辑时删除)
7.6 hello进程fork时的内存映射
(以下格式自行编排,编辑时删除)
7.7 hello进程execve时的内存映射
(以下格式自行编排,编辑时删除)
7.8 缺页故障与缺页中断处理
(以下格式自行编排,编辑时删除)
7.9动态存储分配管理
(以下格式自行编排,编辑时删除)
Printf会调用malloc,请简述动态内存管理的基本方法与策略。
7.10本章小结
(以下格式自行编排,编辑时删除)
(第7章 2分)
第8章 hello的IO管理
8.1 Linux的IO设备管理方法
(以下格式自行编排,编辑时删除)
设备的模型化:文件
设备管理:unix io接口
8.2 简述Unix IO接口及其函数
(以下格式自行编排,编辑时删除)
8.3 printf的实现分析
(以下格式自行编排,编辑时删除)
[转]printf 函数实现的深入剖析 - Pianistx - 博客园
从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall等.
字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。
显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。
8.4 getchar的实现分析
(以下格式自行编排,编辑时删除)
异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。
getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。
8.5本章小结
总结hello所经历的过程如下:
首先需要有一个Hello的胚胎,也就是说先要完成hello.c的C语言源程序的编写。这就是Hello的起点。
下一步使用命令gcc -E进行预处理,Hello完成从hello.c到hello.i的成长。
下一步使用命令gcc -S进行编译,Hello完成从hello.i到hello.s的成长。
下一步使用命令gcc -c进行汇编,Hello完成从hello.s到hello.o的成长。此时的Hello已经变成一个二进制文件了。
对Hello进行链接,将Hello的好伙伴们和Hello联系起来,把它和其他可重定位二进制文件合体,变成一个可以在计算机上运行的二进制文件。
打开Shell,输入命令./hello 120L020629 石博文 99来运行Hello程序。
Shell进行第六章中讲述的一系列判断:首先判断输入命令是否为内置命令。经过检查后发现其不是内置命令,则Shell将其当作程序执行。
随机Shell调用Fork()函数为Hello创建一个进程。
shell调用execve函数,execve函数会将新创建的子进程的区域结构删除,然后将其映射到hello程序的虚拟内存,然后设置当前进程上下文中的程序计数器,使其指向hello程序的入口点。
运行hello时,内存管理单元、TLB、多级页表机制、三级cache协同工作,完成对地址的翻译和请求。
当Hello运行到printf这一步时,操作系统会调用malloc函数从堆中申请内存。
当Hello执行时,可以通过IO输入等操作向进程发送信号。例如我们从键盘输入Ctrl-c,就会发送一个SIGINT信号,使当前前台进程的作业中断;同样哦们可以使用命令jobs来查看被抢占的进程,使用命令fg %<pid>来恢复对应ID的进程。
当进程执行结束后,由父进程对子进程进行回收。至此,Hello的一生结束。
(第8章1分)
结论
用计算机系统的语言,逐条总结hello所经历的过程。
你对计算机系统的设计与实现的深切感悟,你的创新理念,如新的设计与实现方法。
(结论0分,缺失 -1分,根据内容酌情加分)
附件
hello.c 储存hello程序源代码
hello.i 源代码经过预处理产生的文件
hello.s hello程序对应的汇编语言文件
hello.o 可重定位目标文件
hello_o.s hello.o的反汇编语言文件
hello.elf hello.o的ELF文件
hello 可执行文件
hello.elf 可执行文件的ELF文件格式
hello.s 可执行文件的汇编语言文件
(附件0分,缺失 -1分)
参考文献
为完成本次大作业你翻阅的书籍与网站等
[1]Randal E. Bryant, David R. O'Hallaon. 深入理解计算机系统. 第三版. 北京市:机械工业出版社[M]. 2018: 1-737
[2]https://blog.csdn.net/will130/article/details/50917166?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165235876916780366591062%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=165235876916780366591062&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-2-50917166-null-null.142^v9^control,157^v4^control&utm_term=%E9%80%BB%E8%BE%91%E5%9C%B0%E5%9D%80%E3%80%81%E7%BA%BF%E6%80%A7%E5%9C%B0%E5%9D%80%E3%80%81%E8%99%9A%E6%8B%9F%E5%9C%B0%E5%9D%80%E3%80%81%E7%89%A9%E7%90%86%E5%9C%B0%E5%9D%80&spm=1018.2226.3001.4187
[3]https://blog.csdn.net/weixin_41019383/article/details/98207386?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165235934416781667899564%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=165235934416781667899564&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-5-98207386-null-null.142^v9^control,157^v4^control&utm_term=+%E7%BA%BF%E6%80%A7%E5%9C%B0%E5%9D%80%E5%88%B0%E7%89%A9%E7%90%86%E5%9C%B0%E5%9D%80%E7%9A%84%E5%8F%98%E6%8D%A2-%E9%A1%B5%E5%BC%8F%E7%AE%A1%E7%90%86&spm=1018.2226.3001.4187
(参考文献0分,缺失 -1分)