计算机系统
大作业
题 目 程序人生-Hello’s P2P
专 业 2+X人工智能
学 号
班 级 21WL024
学 生
指 导 教 师 郑贵滨
计算机科学与技术学院
2023年5月
本文从普通的hello程序出发,利用edb等工具,分析hello程序从hello.c开始,经历预处理,编译,汇编,链接等过程最终生成可执行文件的全过程。同时其中涉及了计算机系统的进程管理,储存管理,I/O管理。对计算机系统做到更加深刻的理解。
关键词:计算机系统;Hello.c;
目 录
第1章 概述
(0.5分)
1.1 Hello简介
P2P:Hello.c是写好的程序的文本文件,编写Hello.c的过程即program.之后,hello.c经过cpp预处理生成hello.i。经过编译器编译后生成hello.s。之后由汇编器重定位为hello.o。最后由链接器与库函数链接的到可执行文件hello。之后在shell中启动hello程序时,shell为hello程序fork一个子进程,hello由程序变为进程。即From Program to Process。
020:shell首先fork一个子进程,然后通过execve加载并执行Hello,映射虚拟内存,进入程序入口后将程序载入物理内存,进入main函数执行目标代码,CPU为运行的Hello分配时间片执行逻辑控制流。当程序运行结束后,shell父进程负责回收Hello进程,内核删除相关数据结构。即从0开始,以0结束,为020。
1.2 环境与工具
1.2.1 硬件环境
X64 CPU;2GHz;2G RAM;256GHD Disk 以上
1.2.2 软件环境
Windows10 64位;VirtualBox/Vmware 11以上;Ubuntu 16.04 LTS 64位/优麒麟64位以上
1.2.3 开发工具
Visual Studio 2010 64位以上;CodeBlocks 64位;vi/vim/gedit+gcc
1.3 中间结果
hello.i:hello.c预编译的结果,用于研究预编译的作用以及进行编译器的下一步编译操作。
hello.s:hello.i编译后的结果,用于研究汇编语言以及编译器的汇编操作,可以与hello.c对应,分析底层的实现。
hello.o:hello.s汇编后的结果,可重定位目标程序,没有经过链接,用于链接器或编译器链接生成最终可执行程序。
hello.out:hello.o链接后生成的可执行目标文件,可以用来反汇编或者通过EDB、GDB等工具分析链接过程以及程序运行过程,包括进入main函数前后发生的过程。
1.4 本章小结
本章主要介绍hello的p2p,020过程,并提示为写这篇论文而生成的中间结果文件的名字,文件的作用等有关此次实验的信息。
第2章 预处理
(0.5分)
2.1 预处理的概念与作用
前处理是编译前执行的处理。事前处理有三个主要方面。
1.宏定义:定义特定内容的标识符。前处理将源代码中显示的标识符替换为宏观上定义的值。宏观可定义为表示值或类似函数的全球符号。
2.包含文件:#include前处理指示器根据指示扩展包含的文件。
3.条件编译:有条件的编译指南用于确定是否是编译过的代码。
前处理器(cpp)根据字符#开头的命令修改原来的C程序。例如,#include命令指示前处理器读取系统头文件stdio。他的内容直接插入到程序文本中。这将创建另一个C应用程序,用于作为文件扩展名。
2.2在Ubuntu下预处理的命令
正在上传…重新上传取消
2.3 Hello的预处理结果解析
我们使用gedit查看预处理的结果文件hello.i如下:
观察到所有的#include等语句全部被替换,取而代之的是一些路径以及用到的相关语句被插入了该文本。并且在代码中插入注释后进行重新预处理并向下观察可以发现,预处理同时也删除了所有的注释信息。
正在上传…重新上传取消
2.4 本章小结
本章主要介绍了预处理的定义与作用、并结合预处理之后的程序对预处理结果进行了解析。
第3章 编译
(2分)
3.1 编译的概念与作用
编译阶段是编译器对.i文件进行处理的过程。此阶段编译器会完成一系列对代码的语法和语义的分析,生成汇编代码,并保存在.s文件中。
1.语法检查:检查源程序是否合乎语法。如果不符合语法,编译程序要指出语法错误的部位、性质和有关信息。编译程序应使用户一次上机,能够尽可能多地查出错误。
2.调试措施:检查源程序是否合乎设计者的意图。为此,要求编译程序在编译出的目标程序中安置一些输出指令,以便在目标程序运行时能输出程序动态执行情况的信息,如变量值的更改、程序执行时所经历的线路等。这些信息有助于用户核实和验证源程序是否表达了算法要求。
3.修改手段:为用户提供简便的修改源程序的手段。编译程序通常要提供批量修改手段(用于修改数量较大或临时不易修改的错误)和现场修改手段(用于运行时修改数量较少、临时易改的错误)。
3.2 在Ubuntu下编译的命令
正在上传…重新上传取消
3.3 Hello的编译结果解析
汇编指令
.file --------------C文件声明
.text --------------代码段
.globl ------------声明全局变量
.data -------------已初始化的全局和静态C变量
.align 4 ----------声明对指令或者数据的存放地址进行对齐的方式
.type -------------指明函数类型或对象类型
.size -------------- 声明变量大小
.long .string----- 声明long型、string型数据
.section .rodata -- 只读数据段
正在上传…重新上传取消
1.数据初始化
正在上传…重新上传取消
这一部分能够看出Hello的后面是两个%s类型的字符串,对应着我们输入的前两个变量:学号和姓名。
正在上传…重新上传取消
这个位置就是循环变量i声明以及变化,用以完成循环的操作其中也能够看出i所存储的位置是在-4(%rbp)的位置。
2.变量
正在上传…重新上传取消
可以看出共计两个变量,其中argc被存储在了-20(%rbp)的位置,argv被存储在了-32(%rbp)的位置。
3.赋值
正在上传…重新上传取消
根据上文,结合这段汇编代码可知把存储在-4(%rbp)位置的i赋值为0。其中movl中的后缀l是经常用的,表示操作的对象是四个字节,其余的后缀还有b,w,q,分别对应一个,两个,八个字节。
4.计算
正在上传…重新上传取消
图片中的call行是循环的最后一条语句,addl行即为对于循环变量i进行操作。这一句即为i++对应的汇编语句。
5.比较
正在上传…重新上传取消
结合上文分析可知,cmpl行比较的是存储于-20(%rbp)的参数(argc)与4的大小,对应到的是程序中argc!=4的语句。
正在上传…重新上传取消
结合上文分析可知,cmpl行比较的是存储于-4(%rbp)的参数(i)与7的大小,对应到的是循环结束的判定,(i<8也即i≤7)。
6.函数语句
main函数
正在上传…重新上传取消
传参为argc和argv,如上文分析,分别存储在-20(%rbp)和-32(%rbp)中。返回值存储在%eax中。
if语句
正在上传…重新上传取消
判断argc是否为4,若是执行后续操作,若不是则直接跳出if执行后文。
for循环语句
正在上传…重新上传取消
每次循环前判断i<8是否成立,成立则执行for循环内部语句,不成立则跳出循环执行后文。
printf函数
正在上传…重新上传取消
该函数直接通过call进行调用。
exit函数
正在上传…重新上传取消
该函数同样通过call直接进行调用。对应到的是main函数中的exit(1)语句。
atoi函数
正在上传…重新上传取消
该函数同样通过call直接进行调用。该函数的作用是把一个字符串转换成整数类型。
sleep函数
正在上传…重新上传取消
该函数同样通过call直接进行调用,传参数量为1,是休眠的秒数。
getchar函数
正在上传…重新上传取消
该函数同样通过call直接进行调用,不用传参,直接使用即可。
3.4 本章小结
本章主要用汇编语言指示语、数据类型、汇编语言作业、控制传输、函数作业和类型转换等文本文件hello.s的特定操作来描述预先进程文本文件。
第4章 汇编
(2分)
4.1 汇编的概念与作用
概念:汇编指的是汇编器(Assembler)将hello.s翻译成机器语言指令,把这些指令打包成可重定位目标文件,并将结果保存在目标文件hello.o中。hello.o文件是一个二进制文件,包含hello程序执行的机器指令。
作用:将在hello.s中保存的汇编代码翻译生成机器语言,因为机器语言是计算机能直接识别和执行的一种语言。
4.2 在Ubuntu下汇编的命令
正在上传…重新上传取消
4.3 可重定位目标elf格式
1.通过命令导出hello.o的elf文件通过命令导出hello.o的elf文件
正在上传…重新上传取消
2.elf头
正在上传…重新上传取消
3.节头表
正在上传…重新上传取消
节头表描述了.o文件中每一个节出现的位置、大小,目标文件中的每一个节都有一个固定大小的条目。
4.重定位信息
正在上传…重新上传取消
重定位是将EFL文件中的未定义符号关联到有效值的处理过程。在hello.o中,对printf,exit等函数的未定义的引用和全局变量替换为该进程的虚拟地址空间中机器代码所在的地址。
5.符号表
正在上传…重新上传取消
符号表是用来存放程序中定义和引用的函数和全局变量的信息。重定位需要引用的符号都在其中声明。
4.4 Hello.o的结果解析
正在上传…重新上传取消
使用gedit将其打开得到结果。
1.分支转移
正在上传…重新上传取消
反汇编代码跳转指令的操作数使用的不是段名称如.L2,段名称只是在汇编语言中便于编写的助记符,在汇编成机器语言之后使用地是确定的地址。
2.函数调用
正在上传…重新上传取消
在.s文件中,函数调用之后直接跟着函数名称,而在反汇编程序中,call的目标地址是当前下一条指令。这是因为hello.c中调用的函数最终需要通过动态链接器才能确定函数的运行时执行地址,在汇编成为机器语言的时候,对于这些不确定地址的函数调用,将其call指令后的相对地址设置为全0,然后在.rela.text节中为其添加重定位条目,在链接后再进一步确定。
3.全局变量访问
正在上传…重新上传取消
在.s文件中,访问.rodata(printf中的字符串),使用段名称+%rip,在反汇编代码中0+%rip,因为.rodata中数据地址也是在运行时确定,故访问也需要重定位。所以在汇编成为机器语言时,将操作数设置为全0并添加重定位条目。
4.5 本章小结
本章介绍了程序生成过程中编译器汇编的相关内容。汇编过程将汇编语言转换为机器代码,生成可重定位的目标文件,使机器能够直接处理与执行。可以通过readelf读取其elf信息与重定位信息,得到其符号表的相关信息。另外,可以通过objdump反汇编目标文件,从中可以得到机器代码与汇编代码的对照。
第5章 链接
(1分)
5.1 链接的概念与作用
概念:链接指的是计算机程序中各个模块之间传递参数和控制命令,将程序编码和数据收集整理为一个单一的文件,生成可执行目标文件的过程。
作用:链接方便了程序的修改和编译,可以让我们独立的编译某一小部分的代码,并重新链接应用。
5.2 在Ubuntu下链接的命令
正在上传…重新上传取消
5.3 可执行目标文件hello的格式
正在上传…重新上传取消
1. elf头
正在上传…重新上传取消
2.节头表
正在上传…重新上传取消
正在上传…重新上传取消
3.重定位节
正在上传…重新上传取消
4.符号表
正在上传…重新上传取消
正在上传…重新上传取消
5.程序头
正在上传…重新上传取消
5.4 hello的虚拟地址空间
与节头表对应的部分:
正在上传…重新上传取消
可以发现程序的虚拟地址从0x401000开始到0x402000结束,这与.elf文件的节头表部分正好完全对应。此外查看symbols选项也能发现程序各部分的地址都可以与.elf的节头表完全对应。
正在上传…重新上传取消
5.5 链接的重定位过程分析
将它与hello.o文件的反汇编代码进行比较后,可得下面不同:
1.地址的访问:hello.o中的相对地址到了hello中变成了虚拟内存地址。而hello.o文件中对于.rodata的访问,是$0x0和0(%rip),是因为它们的地址也是在运行时确定的,因此访问也需要重定位,在汇编成机器语言时,将操作数全置为0,并且添加重定位条目。
2.链接增加新的函数:在hello中链接加入了在hello.c中用到的函数,如exit、printf、sleep、getchar等函数。
3.增加的节:hello中增加了.init和.plt节,和一些节中定义的函数。
4.函数调用:hello中无hello.o中的重定位条目,并且跳转和函数调用的地址在hello中都变成了虚拟内存地址。对于hello.o的反汇编代码,函数只有在链接之后才能确定运行执行的地址,因此在.rela.text节中为其添加了重定位条目。
重定位过程
1.关联符号定义
链接器将代码中的每个符号引用和一个符号定义关联起来。此时,链接器知道输入目标模块中的代码节和数据节的确切大小。
2.合并输入模块
链接器将所有输入到hello中相同类型的节合并为同一类型的新的聚合节。
3.符号引用
链接器修改hello中的代码段和数据段中对每一个符号的引用,使其指向正确的运行地址。
正在上传…重新上传取消
5.6 hello的执行流程
_init 0x401000
.plt 0x401020
puts@plt 0x401030
exit@plt 0x401060
_printf_chk_@plt 0x4010b0
sleep@plt 0x401070
getc@plt 0x4010e0
_start 0x4010f0
main 0x4011d6
_libc_csu_init 0x401260
_libc_csu_fini 0x4012d0
_fini 0x4012d8
5.7 Hello的动态链接分析
动态链接的基本思想是把程序按照模块拆分成各个相对独立部分,在程序运行时才将它们链接在一起形成一个完整的程序,而不是像静态链接一样把所有程序模块都链接成一个单独的可执行文件。虽然动态链接把链接过程推迟到了程序运行时,但是在形成可执行文件时,还是需要用到动态链接库。比如我们在形成可执行程序时,发现引用了一个外部的函数,此时会检查动态链接库,发现这个函数名是一个动态链接符号,此时可执行程序就不对这个符号进行重定位,而把这个过程留到装载时再进行。
在调用共享库函数时,编译器没有办法预测这个函数的运行时地址,因为定义它的共享模块在运行时可以加载到任意位置。正常的方法是为该引用生成一条重定位记录,然后动态链接器在程序加载的时候再解析它。GNU编译系统使用延迟绑定,将过程地址的绑定推迟到第一次调用该过程时。
延迟绑定是通过GOT和PLT实现的。GOT是数据段的一部分,而PLT是代码段的一部分。两表内容分别为:
PLT:PLT是一个数组,其中每个条目是16字节代码。PLT[0]是一个特殊条目,它跳转到动态链接器中。每个被可执行程序调用的库函数都有它自己的PLT条目。每个条目都负责调用一个具体的函数。
GOT:GOT是一个数组,其中每个条目是8字节地址。和PLT联合使用时,GOT[0]和GOT[1]包含动态链接器在解析函数地址时会使用的信息。GOT[2]是动态链接器在1d-linux.so模块中的入口点。其余的每个条目对应于一个被调用的函数,其地址需要在运行时被解析。每个条目都有一个相匹配的PLT条目。
正在上传…重新上传取消
5.8 本章小结
本章主要介绍了链接的过程,可重定位文件经过静态链接以及动态链接后成为了可执行程序。链接后的代码体积变小。通过对各种文件即反汇编文件的分析,对链接的文件变化有了更深入的认识。
第6章 hello进程管理
(1分)
6.1 进程的概念与作用
概念:计算机程序需要进行对数据集合进行操作所运行的一次活动
作用:是操作系统的基础,是系统进行资源分配和调度的基本单位
6.2 简述壳Shell-bash的作用与处理流程
Shell俗称壳,是一种指“为使用者提供操作界面”的嵌入式软件。软件提供了一种允许用户与其他操作系统之间进行通讯的一种方式。这种简单的通讯方式可以以交互方式,或者以非交互的方式允许用户执行。shell是一个简单的命令解释器,它允许系统接收到一个用户的命令,然后自动调用相应的命令执行应用程序。
Shell的处理流程:shell读取用户从终端使用外部设备输入的指令。解析所读取的指令,如果这个指令是一个内部指令则立即执行,否则,加载调用一个应用程序为申请的程序创建新的子进程,在子进程的上下文中运行。同时shell还允许接收从键盘读入的外部信号,并根据不同信号的功能进行对应的处理。
6.3 Hello的fork进程创建过程
Shell(父进程)通过fork函数创建一个新的运行的子进程。新的子进程几乎但不完全与父进程相同。子进程得到与父进程用户级虚拟地址空间相同的一份副本,包括代码和数据段、堆、共享库以及用户栈。子进程进程还获得与父进程任何打开文件描述符相同的副本,这就意味着当父进程调用fork时,子进程可以读写父进程中打开的任何文件。
6.4 Hello的execve过程
execve函数加载并运行可执行目标文件filename,且带参数列表argv和环境变量列表envp。只有当出现错误时,例如找不到filename,execve才会返回到调用程序。所以,与fork一次调用返回两次不同,execve调用一次并从不返回。
execve调用驻留在内存中的被称为启动加载器的操作系统代码来执行程序,加载器删除子进程现有的虚拟内存段,并创建一组新的代码、数据、堆和栈段。新的栈和堆段被初始化为零,通过将虚拟地址空间中的页映射到可执行文件的页大小的片,新的代码和数据段被初始化为可执行文件中的内容。最后加载器设置PC指向_start地址,_start最终调用main函数。除了一些头部信息,在加载过程中没有任何从磁盘到内存的数据复制。直到CPU引用一个被映射的虚拟页时才会进行复制,这时,操作系统利用它的页面调度机制自动将页面从磁盘传送到内存。
6.5 Hello的进程执行
execve函数将hello中的.text节、.data节、.bss节等内容加载到当前进程的虚拟地址空间后,加载器跳转到hello程序的入口点,开始执行hello进程。在hello进程执行过程中的某些时刻,可能会执行exit(1)或sleep()系统调用。
sleep系统调用,显式地请求让调用进程休眠,从而可能会触发内核进行调度。sleep函数会让调用进程休眠较长的一段时间,所以内核执行从hello进程到某个进程B的上下文切换。在切换进程之前,内核正代表hello进程在用户模式下执行指令。在切换的第一部分中,内核代表hello进程在用户模式下执行指令。然后再某一时刻,内核保存hello进程的上下文,加载进程B及其上下文,内核开始代表进程B在用户模式下执行指令。
进程B在用户模式下运行一段时间后,内核判断sleep函数调用已经终止,就执行进程B到hello进程的上下文切换,操作系统恢复hello进程的上下文,将控制返回给hello进程中紧随在系统调用sleep后的那条指令。hello进程继续运行,直到下一次异常发生,以此类推。
6.6 hello的异常与信号处理
1.中断
中断是异步发生的,是来自处理器外部的I/O设备的信号的结果。硬件中断不是由任何一条专门的指令造成的,从这个意义上来说它是异步的。硬件中断的异常处理程序常常称为中断处理程序。
2.陷阱
陷阱是有意的异常,是执行一条指令后的结果。就像中断处理程序一样,陷阱处理程序将控制返回到下一条指令。陷阱最重要的用途是在用户程序和内核之间提供一个像过程一样的接口,叫做系统调用。
3.故障
故障由错误情况引起,它可能能够被故障处理程序修正。当故障发生时,处理器将控制转移给故障处理程序。如果故障处理程序能够修正这个错误,它就将控制返回给引起故障的指令,从而重新执行它,否则,处理程序返回到内核中的abort例程,abort例程会终止引起故障的应用程序。
4.终止
终止是不可恢复的致命错误造成的结果,通常是一些硬件错误,比如DRAM或者SRAM位被损坏时发生的奇偶错误。终止处理程序不会将控制返回给应用程序。
(1)输入回车
正在上传…重新上传取消
可以发现回车和随机字符串对于程序的运行并没有影响,终端中会出现所有相关的输入,此外如果随机字符串搭配回车一起输入,每个回车会被终端识别为一条新的指令,并不会影响到现有程序运行。
- 输入Ctrl+C
正在上传…重新上传取消
当向hello程序输入Ctrl+C后,会导致中断异常产生SIGINT信号,向子进程发出SIGKILL信号终止并回收,进程会终止。
- 输入Ctrl+Z
正在上传…重新上传取消
当向hello程序输入Ctrl+Z后,会导致中断异常产生SIGSTP信号,进程被挂起,与输入Ctrl+C结果不同。此时分别输入。
- ps指令
正在上传…重新上传取消
可以看出hello进程并未停止,而是被挂起。在进程列表中仍然可以看到hello这个进程。究其原因是SIGTSTP是一个暂时停止的信号,如果该进程接收到一个SIGCONT信号就会继续运行。故该进程只是被挂起,而并没有如上文所提被父进程或者是init进程被回收。
- jobs指令
正在上传…重新上传取消
通过本指令验证hello进程确实被挂起,处于停止的状态。
- pstree指令
正在上传…重新上传取消
正在上传…重新上传取消
正在上传…重新上传取消
可以通过调出进程树来查看所有进程的情况。
- fg指令
正在上传…重新上传取消
fg指令的用处是使第一个后台作业变成前台作业,正巧这里hello是第一个后台作业,所以fg会使得hello回到前台并完成运行。
(8)kill指令
正在上传…重新上传取消
kill指令成功杀死进程hello,从进程列表以及提示的信息中均可得知。
6.7本章小结
本章中阐述了进程的概念以及他在计算机中具体是如何在使用的。其次,还介绍了如何利用shell这个平台来对进程进行监理调用或发送信号等一系列操作。
第7章 hello的存储管理
( 2分)
7.1 hello的存储器地址空间
结合hello说明逻辑地址、线性地址、虚拟地址、物理地址的概念。
逻辑地址:访问指令给出的地址 (操作数) 叫逻辑地址,也叫相对地址,由选择符和偏移量组成。要经过寻址方式的计算或变换才得到内存储器中的物理地址。
线性地址:地址空间内的地址应当是整数连续的,上一个地址到下一个地址变化不得超过1。
虚拟地址:操作系统为每个进程构造出一个虚拟内存空间,在虚拟内存空间寻址使用虚拟地址。
物理地址:在寻址进程实际储存在物理内存使用的物理内存时需要使用的地址。
7.2 Intel逻辑地址到线性地址的变换-段式管理
一个逻辑地址由两部分组成:段选择符和段内偏移量。
段选择符是由一个16位长的字段组成,称为段选择符。其中前13位是一个索引号。TI:0为GDT,1为LDT。Index指出选择描述符表中的哪个条目,RPL请求特权级。
最初8086处理器的寄存器是16位的,为了能够访问更多的地址空间但不改变寄存器和指令的位宽,所以引入段寄存器,8086共设计了20位宽的地址总线,通过将段寄存器左移4位加上偏移地址得到20位地址,这个地址就是逻辑地址。将内存分为不同的段,段有段寄存器对应,段寄存器有一个栈、一个代码、两个数据寄存器。
7.3 Hello的线性地址到物理地址的变换-页式管理
CPU的页式内存管理单元,负责把一个线性地址,最终翻译为一个物理地址。从管理和效率的角度出发,线性地址被分为以固定长度为单位的组,称为页(page),例如一个32位的机器,线性地址最大可为4G,可以用4KB为一个页来划分,这页,整个线性地址就被划分为一个tatol_page[2^20]的大数组,共有2的20个次方个页。这个大数组我们称之为页目录。目录中的每一个目录项,就是一个地址——对应的页的地址。另一类“页”,我们称之为物理页,或者是页框、页桢的。是分页单元把所有的物理内存也划分为固定长度的管理单位,它的长度一般与内存页是一一对应的。
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支持下的物理内存访问
在Intel Core i7处理器的cache的每个CPU芯片有四个核,每个核有自己私有的L1 i-cache、L1 d-cache和L2统一的高速缓存。所有的核共享片上L3统一的高速缓存。这个层次结构的一个有趣的特性是所有的SRAM高速缓存存储器都在CPU芯片上。L1、L2和L3高速缓存是物理寻址的,块大小为64字节。L1和L2是8路组相联的,而L3是16路组相联的。其运作原理为使用更快的存储设备来保留从较慢的存储设备读取的数据的副本。当数据需要从较慢的存储设备读写时,缓存允许读写首先在较快的存储设备上完成,从而提高系统的响应能力。
7.6 hello进程fork时的内存映射
mm_struct(内存描述符):描述了一个进程的整个虚拟内存空间。
vm_area_struct(区域结构描述符):描述了进程的虚拟内存空间的一个区间。
在用fork创建内存的时候,我们需要以下三个步骤:
1.创建当前进程的mm_struct,vm_area_struct和页表的原样副本。
2.两个进程的每个页面都标记为只读页面。
3.两个进程的每个vm_area_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.8 缺页故障与缺页中断处理
1.处理器生成一个虚拟地址,并将它传送给MMU。
2.MMU生成PTE地址,并从高速缓存/主存请求得到它。
3.高速缓存/主存向MMU返回PTE。
4.PTE中的有效位是0,所以MMU出发了一次异常,传递CPU中的控制到操作系统内核中的缺页异常处理程序。
5.缺页处理程序确认出物理内存中的牺牲页,如果这个页已经被修改了,则把它换到磁盘。
6.缺页处理程序页面调入新的页面,并更新内存中的PTE。
7.缺页处理程序返回到原来的进程,再次执行导致缺页的命令。CPU将引起缺页的虚拟地址重新发送给MMU。因为虚拟页面已经换存在物理内存中,所以就会命中。
7.9本章小结
本章分析了hello的存储管理。介绍了Intel逻辑地址到线性地址的变换-段式管理,以及TLB与多级页表支持下的VA到PA的转换,分析了三级Cache支持下的物理内存访问。简要分析了hello的fork和execve内存映射,介绍了缺页故障与缺页中断处理程序的相关知识。
结论
(0分,必要项,如缺失扣1分,根据内容酌情加分)
hello源程序在.c文件中被编写,创建了hello.c文件。之后hello.c文件交付gcc进行编译形成可执行文件。
首先hello.c被cpp进行预处理,执行了预处理指令,删除了相关的注释,生成了hello.i文件。
之后由ccl对hello.i文件进行编译,翻译成相应的汇编代码,并为后期生成.o文件做准备。生成.s文件。
hello.s文件又通过as进行汇编,将汇编代码翻译成机器代码,并生成代码段数据段等段信息以及用于链接的重回定位条目。生成.o可重定位目标文件。
hello.o由ld进行链接处理,对hello.o程序中的符号和函数进行重定位。加载链接相应的共享函数等等。生成真正的可执行文件hello。
之后在shell中输入./hello命令执行hello程序,shellfork出一个新进程,并且将hello交付execve和加载器加载到内存里。
执行指令后又会有中断,陷阱,故障,终止,信号等一系列改变控制流的事件,进行上下文切换。
执行指令时又会访问内存数据,进行VA到PA翻译,cache命中与不命中的事件。
最后hello程序执行结束。父进程shell回收hello进程,操作系统删除内存中一切与hello进程有关的数据。
附件
列出所有的中间产物的文件名,并予以说明起作用。
hello.i 预处理生成的文本文件
hello.s .i文件编译后得到的汇编语言文件
hello.o .s文件汇编后得到的可重定位目标文件
hello .o经过链接生成的可执行目标文件
hello.objdump 可执行文件经过链接反汇编的汇编语言文件
disasm_hello.s .o经过反汇编生成的汇编语言文件
elf.txt .o的elf文本文件
hello.elf hello的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分)