计算机系统

大作业

题     目 程序人生-Hello’s P2P

专       业 计算机类

学     号 120L021923

班     级 2003006

学       生 甄自镜    

指 导 教 师 吴锐   

计算机科学与技术学院

2021年5月

摘  要

本文对hello.c在linux下的运行的整个生命周期进行分析,从编写完成开始到程序回收结束,介绍了hello从预处理、编译、汇编、链接直到被回收的整个过程及原理,同时介绍了与运行相关的进程管理、存储管理、I/O管理的内容,描绘了hello波澜壮阔的一生

关键词:预处理;编译;汇编;链接;进程管理;存储管理;linux;I/O

(摘要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简介

根据Hello的自白,利用计算机系统的术语,简述Hello的P2P,020的整个过程。

1.建立hello.c文件

2. 预处理器将其进行预处理生成hello.i文件。

3. 编译器编译得到hello.s文件

4. 汇编器汇编得到hello.o

5. 链接器与库函数链接生成一个可执行程序

6.通过shell输入./shell,shell通过fork函数创建了一个新的进程

7. 调用execve映射虚拟内存,通过mmap为hello程序开创了一片空间。

8. CPU从虚拟内存中的.text,.data节取代码和数据,调度器为进程规划时间片,有异常时触发异常处理子程序。

9. .程序运行结束,父进程回收hello进程和它创建的子进程,内核删除相关数据结构。

1.2 环境与工具

列出你为编写本论文,折腾Hello的整个过程中,使用的软硬件环境,以及开发与调试工具。

1.2.1 硬件环境

X64 CPU;2GHz;2G RAM;256GHD Disk 以上

1.2.2 软件环境

Windows7/10 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.c

源程序

hello.i

预处理后的文件

hello.s

汇编文件

hello.o

可重定位目标执行文件

hello

可执行文件

hello.elf

hello.o的ELF格式

hello.txt

hello.o的反汇编语言

hello1.txt

hello的反汇编语言

hello1.elf

hello的ELF格式

1.4 本章小结

本章对hello的一生进行了简要的介绍和描述,介绍了P2P,O2O的整个过程,介绍了计算机硬件环境、软件环境、开发与调试工具,介绍了中间文件的名称即其作用。

(第1章0.5分)

第2章 预处理

2.1 预处理的概念与作用

概念:预处理一般是指在程序源代码被翻译为目标代码的过程中,生成二进制代码之前的过程。

作用:预处理指令一般被用来使源代码在不同的执行环境中被方便的修改或者编译。

2.2在Ubuntu下预处理的命令

图2.2.1

在linux 系统中用gcc -E -o hello.i hello.c进行预处理的命令

2.3 Hello的预处理结果解析

图2.3.1 Hello.i文件截图

分析:hello.c预处理后变为hello.i文件,文件内容如上图所示,文件扩展为三千多行,将原程序中的宏进行了宏展开,对函数的声明,变量定义等信息放在中间,程序的源代码被放到了最后。

2.4 本章小结

本章介绍了预处理的概念与作用,学习了用gcc对hello.c文件进行预处理,将其重定向到hello.i中,并且分析了hello.i文件中的内容

(第2章0.5分)

第3章 编译

3.1 编译的概念与作用

概念:编译程序所要作得工作就是通过词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示或汇编代码。

作用:

1.语法分析:编译程序的语法分析器以单词符号作为输入,分析单词符号串是否形成符合语法规则的语法单位。

2.中间代码:源程序的一种内部表示,或称中间语言。中间代码的作用是可使编译程序的结构在逻辑上更为简单明确,特别是可使目标代码的优化比较容易实现中间代码。

3.代码优化:指对程序进行多种等价变换,使得从变换后的程序出发,能生成更有效的目标代码。

4.目标代码:生成是编译的最后一个阶段。目标代码生成器把语法分析后或优化后的中间代码变换成目标代码。此处指汇编语言代码,须经过汇编程序汇编后,成为可执行的机器语言代码。

3.2 在Ubuntu下编译的命令

图3.2.1

在linux 系统中用gcc -S hello.i -o hello.s进行编译的命令

3.3 Hello的编译结果解析

3.3.1汇编第一部分:

   图3.3.1

file:声明源文件

text:代码节

section:指示把代码划分成若干个段(Section)

rodata:只读代码段,后面是printf()与scanf()中存储的字符串。

align:数据或者指令的地址对其方式

string:声明一个字符串LC0,LC1

global:声明全局变量(main)

type:声明一个符号是数据类型还是函数类型

3.3.2数据

1.字符串:即只读代码段中的两个字符串LC0,LC1。二者作为printf(),scanf()的参数,如图:

图3.3.2

2.整数:

在程序中一共有两个int变量,分别为i与argc

i是一个局部变量,编译器进行编译的时候将局部变量i会放在堆栈中。如图所示,局部变量i放在栈上-4(%rbp)的位置。

Argc是传给main的参数,进入了堆栈

3.立即数,形式为$+常数

3.3.3赋值操作:

利用mov实现,类如:

PS:movb:一个字节

movw:“字”

movl:“双字”

movq:“四字”

3.3.4关系操作和控制转移

Jle:判断cmpl产生的条件码,小于等于7跳转L4

Je:判断cmpl产生的条件码,不等于4则跳转.L2、

3.3.5算术操作:

Add 即i++,图片对应解释为:对i自加,栈上存储变量i的值加1

3.3.6数组/指针/结构操作

主函数main的参数中有指针型数组char *argv[],对此数组的操作通常由mov指令实现。取到argv数组的首地址,然后对首地址加相应字节得到对应的地址,argv[0]指向输入程序的路径和名称,argv[1]和argv[2]分别表示两个字符串。char* 数据类型占8个字节

3.3.7函数操作:

Main函数;传入参数argc和argv[],分别用寄存器%rdi和%rsi存储。被系统启动函数调用。设置%eax为0并且返回,对应return 0 。

Printf:第一处调用由于只是输入一串字符串,所以被优化成puts函数,之后通过call来调用puts,而第二处调用printf,有三个参数,因此我们需要取出参数

Exit:传入参数1后调用函数退出。

Atoi:将字符串类型转换为整型。

Sleep:atoi被调用完后,会将其返回值作为sleep函数的参数,调用sleep。

Getchar:直接调用

3.4 本章小结

介绍了编译的概念以及过程。通过hello函数分析了c语言如何转换成为汇编代码。介绍了汇编代码如何实现变量、常量、传递参数以及分支和循环。

(第32分)

第4章 汇编

4.1 汇编的概念与作用

概念:汇编器将汇编程序翻译成机器语言指令,把这些指令打包成可重定位目标程序的格式,并将结果保存在.o 目标文件中。

作用:将汇编代码转换为机器指令,使其在链接后能被机器识别并执行。

4.2 在Ubuntu下汇编的命令

图4.2.1

在linux 系统中用gcc -c -o hello.o hello.s进行汇编的命令

4.3 可重定位目标elf格式

分析hello.o的ELF格式,用readelf等列出其各节的基本信息,特别是重定位项目分析。

典型ELF可重定位目标文件:

图4.3.1

图4.3.2

在linux 系统中用readelf -a hello.o > hello.elf进行生成elf格式文件的命令

ELF文件格式分析:

1.ELF头:ELF头(ELF header)以一个16B的序列Magic开始,这个序列描述了生成该文件的系统的字的大小和字节顺序。ELF头剩下的部分包含了帮助链接器语法分析和解释目标文件的信息,其中包括ELF头的大小、目标文件的类型(如可重定位、可执行或者共享的)、机器类型(如x86-64)、节头部表(section header table)的文件偏移,以及节头部表中条目的大小和数量。不同节的位置和大小是有节头部表描述的,其中目标文件中每个节都有一个固定大小的条目(entry)。

Hello.elf文件中ELF头:

图4.3.3

2.节头目表:(节头):记录各节名称、类型、地址、偏移量、大小、全体大小、旗标、链接、信息、对齐。 因为是可重定位目标文件,所以每个节都从0开始,用于重定位。

图4.3.4

3.重定位节:各个段引用的外部符号等在链接时需要通过重定位对这些位置的地址进行修改。链接器会通过重定位节的重定位条目计算出正确的地址。

需要重定位有:.rodata中的模式串,puts,exit,printf,slepsecs,sleep,getchar等符号。

图4.3.5

4.符号表:存放在程序中定义和引用的函数和全局变量的信息。编译器中的符号表不同,.symtab符号表不包含局部变量的条目。

图4.3.6

4.4 Hello.o的结果解析

图4.4.1

利用objdump -d -r hello.o >hello.txt 进行反汇编。

机器语言的构成:机器语言是机器能直接识别的程序语言或指令代码,无需经过翻译,每一操作码在计算机内部都有相应的电路来完成它,或指不经翻译即可为机器直接理解和接受的程序语言或指令代码。机器语言使用绝对地址和绝对操作码。不同的计算机都有各自的机器语言,即指令系统。从使用的角度看,机器语言是最低级的语言。

与汇编语言的映射关系:机器语言是用于控制计算机中处理器的实际位,通常被视为十六进制数字序列(通常为字节).处理器从程序存储器中读取这些位,这些位表示下一步操作的"指令".因此,机器语言提供了一种将指令输入计算机的方式

与hello.s的不同:

1.控制转移:

Hello.s

Hello.txt

Hello.s中使用L2这样的段名称进行跳转,而在反汇编中,跳转到函数+偏移量这样的形式。因为段名称在汇编语言中为便于编写的助记符,所以在汇编成机器语言之后就不存在了,而是确定的地址。

2.函数调用

汇编代码中函数调用时直接使用函数名称,而在反汇编的文件中call之后定位到call的下一条指令,即用具体的地址表示。例如:

3.数的表示

hello.s中的操作数表现为十进制,而hello.o反汇编代码中的操作数为十六进制。

4.5 本章小结

本章介绍了汇编。经过汇编器,将汇编语言转化为机器语言,hello.s文件转化为hello.o可重定位目标文件。分析了ELF的文件格式,了解了ELF头等相关概念,分析了汇编语言与机器语言的不同。

(第41分)

第5章 链接

5.1 链接的概念与作用

以下格式自行编排,编辑时删除

注意:这儿的链接是指从 hello.o 到hello生成过程。

概念:链接是将各种不同文件(主要是可重定位目标文件)的代码和数据综合在一起,通过符号解析和重定位等过程,最终组合成一个可以在程序中加载和运行的单一的可执行目标文件的过程。

作用:链接令分离编译成为可能,方便了程序的修改和编译:无需重新编译整个工程,而是仅编译修改的文件。

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的格式

利用readelf -a hello > hello1.elf看ELF Header的具体信息

图5.3.1

1.ELF头

图5.3.2

2.节头

图5.3.3

3.重定位节

图5.3.4

4.符号表

图5.3.5

5.4 hello的虚拟地址空间

使用edb加载hello,查看本进程的虚拟地址空间各段信息,并与5.3对照分析说明。

从data dump中发现虚拟地址从0x401000开始到0x401ff0结束,根据5.3节头部表,可以找到各个节的信息

图5.4.1

5.5 链接的重定位过程分析

objdump -d -r hello 分析hello与hello.o的不同,说明链接的过程。

结合hello.o的重定位项目,分析hello中对其怎么重定位的。

通过objdump -d -r hello >hello1.txt得到hello的反汇编文件hello1.txt

二者的不同:

1.hello1.txt中多了许多节

比如下图中的.int .plt等

图5.5.1

2.文件内容有所不同

Hello已经完成了重定位,因此在调用函数时使用的地址已经是函数的虚拟地址,同时在跳转时也是使用虚拟地址。

图5.5.2

5.6 hello的执行流程

以下格式自行编排,编辑时删除

使用edb执行hello,说明从加载hello到_start,到call main,以及程序终止的所有过程。请列出其调用与跳转的各个子程序名或程序地址。

过程:

0x7ffff7de3f30 <_init>

0x4010f0<_start>

0x4011f1 <in __libc_csu_init>

0x401000<_init>

0x401125 <main>

0x4010a0 printf@pl

0x4010c0 atoi@plt

0x4010e0 sleep@plt

0x4010b0 getchar@plt

0x7ffff7e06a70 <exit>

5.7 Hello的动态链接分析

分析hello程序的动态链接项目,通过edb调试,分析在dl_init前后,这些项目的内容变化。要截图标识说明。

延迟绑定是通过GOT和PLT实现的

由ELF文件可知,got起始表位置为0x403ff0

图5.7.1

调用dl_init前0x403ff0为空

图5.7.2

调用后:

图5.7.3

我们可以发现,0x403ff0出现了变化,存入地址。

5.8 本章小结

本章研究了链接的过程。通过edb查看hello的虚拟地址空间,对比hello与hello.o的反汇编代码,深入研究了链接的过程中重定位的过程。

(第51分)

第6章 hello进程管理

6.1 进程的概念与作用

概念:一个执行程序中的实例,系统中的每个程序都运行在某个进程的上下文中。上下文是由程序正确运行所需的状态组成的。这个状态包括存放在内存中的程序的代码和数据,它的栈、通用目的寄存器的内容、程序计数器、环境变量以及打开文件描述符的集合。

作用:进程提供给应用程序的关键抽象:一个独立的逻辑控制流,如同程序独占处理器;一个私有的地址空间,如同程序独占内存系统。它提供了一个假象,好像我们的程序独占地使用内存系统,处理器好像是无间断的执行我们程序中的指令,我们程序中的代码和数据好像是系统内存中唯一的对象。多进程可以完成多任务,每个进程就好比一家独立的公司,每个公司都各自在运营,每个进程也各自在运行,执行各自的任务。

6.2 简述壳Shell-bash的作用与处理流程

作用:shell是一个交互型应用程序,把用户输入的命令翻译给操作系统。提供了一个界面,用户可以通过这界面访问操作系统内核。

处理流程:shell首先检查命令是否是内部命令,若不是再检查是否是一个应用程序(这里的应用程序可以是Linux本身的实用程序,如ls和rm,也可以是购买的商业程序,如xv,或者是自由软件,如emacs)。然后shell在搜索路径里寻找这些应用程序(搜索路径就是一个能找到可执行程序的目录列表)。如果键入的命令不是一个内部命令并且在路径里没有找到这个可执行文件,将会显示一条错误信息。如果能够成功找到命令,该内部命令或应用程序将被分解为系统调用并传给Linux内核。

6.3 Hello的fork进程创建过程

在我们输入./hello 120L021923 甄自镜 1后,shell将会对我们的命令进行解析,由于我们输入的不是一个内置命令,shell会调用fork(),创建一个子进程,子进程得到与父进程用户级虚拟地址空间相同的但是独立的一份副本,然后开始执行程序。

6.4 Hello的execve过程

子进程创建完毕后,会去调用execve()来加载可执行文件到当前进程。然后删除已存在的用户区域。删除之前进程在用户部分中已存在的结构。创建新的区域结构:通过虚拟内存机制将可执行文件hello中的各个段映射到对应的代码段、数据段等地址空间。然后通过跳转到hello程序的第一条指令或入口点来运行该程序,由此将控制传递给新程序的主函数。

6.5 Hello的进程执行

结合进程上下文信息、进程时间片,阐述进程调度的过程,用户态与核心态转换等等。

进程上下文信息:当进程调度一个新的进程运行后,会使用上下文切换来将控制转移到新的进程。上下文切换会:1.保存当前进程的上下文。2.恢复某个先前被抢占进程的被保存的上下文。3.将控制传递给新进程。系统调用、中断可能引起上下文切换。

进程时间片:一个进程执行它的控制流的一部分的每一时间段叫做时间片。

进程调度的过程:在对进程进行调度的过程,操作系统主要做两件事:加载保存的寄存器,切换虚拟地址空间。

用户态与核心态转换:处理器通常使用一个寄存器提供两种模式的区分,该寄存器描述了进程当前享有的特权,当没有设置模式位时,进程就处于用户模式中, 用户模式的进程不允许执行特权指令,也不允许直接引用地址空间中内核区内的代码和数据;设置模式位时,进程处于内核模式,该进程可以执行指令集中的任何命令,并且可以访问系统中的任何内存位置。

具体过程如下:输入命令./hello 120L021923 甄自镜 ,然后调用sleep()函数进入内核模式,进行信号处理,然后返回用户模式,运行过程中,cpu不断切换上下文,使运行过程被切分成时间片,与其他进程交替占用cpu,实现进程的调度。

图6.5.1

6.6 hello的异常与信号处理

hello执行过程中会出现哪几类异常,会产生哪些信号,又怎么处理的。

程序运行过程中可以按键盘,如不停乱按,包括回车,Ctrl-Z,Ctrl-C等,Ctrl-z后可以运行ps  jobs  pstree  fg  kill 等命令,请分别给出各命令及运行结截屏,说明异常与信号的处理。

1.异常

异常和信号异常可以分为四类:中断、陷阱、故障、终止

中断:处理器外部I/O设备引起,异步异常,例如:时钟中断,键盘上敲击Ctrl-C.

陷阱:有意的异常,执行指令产生的结果,发生时间可预知,同步异常,例如:系统调用。

故障:不是有意的,但可能被修复,同步异常,例如:缺页故障,保护故障。

终止:非故意,不可恢复非致命错误造成,例如:非法指令,奇偶校验错误。

2.各种键盘操作导致的异常:

正常:

图6.6.1

回车

图6.6.2

Ctrl Z 默认结果是挂起前台的作业,hello进程并没有回收,而是运行在后台下

图6.6.3

Ps

图6.6.4

Jobs

图6.6.5

Pstree

图6.6.6

Fg

图6.6.7

Kill 挂起的进程被终止,在ps中无法查到到其PID。

图6.6.8

Ctrl C

图6.6.9

PS:运行了两个hello,因此显示有两个

6.7本章小结

本章介绍了进程的概念和作用,以及壳Shell-bash的作用与处理流程,调用 fork 创建新进程,调用 execve函数执行 hello,最后介绍了执行过程中的异常与信号处理。

(第61分)

第7章 hello的存储管理

7.1 hello的存储器地址空间

逻辑地址:指由程序产生的与段相关的偏移地址部分。在这里指的是hello.o中的内容。

线性地址:逻辑地址到物理地址变换之间的中间层。程序hello的代码会产生段中的偏移地址,加上相应段的基地址就生成了一个线性地址。

虚拟地址:是Windows程序时,运行在保护模式下,这样程序访问存储器所使用的逻辑地址称为虚拟地址,与实地址模式下的分段地址类似,虚拟地址也可以写为“段:偏移量”的形式,这里的段是指段选择器。Hello反汇编的地址即为虚拟地址。

物理地址:CPU通过地址总线的寻址,找到真实的物理内存对应地址。CPU对内存的访问是通过连接着CPU和北桥芯片的前端总线来完成的。在前端总线上传输的内存地址都是物理内存地址。

7.2 Intel逻辑地址到线性地址的变换-段式管理

一个逻辑地址由两部份组成,段标识符,段内偏移量。段标识符是一个16位长的字段,又被称为段选择符。其中前13位是一个索引号。可以通过段标识符的索引号,直接在段描述符表中找到一个具体的段描述符,这个描述符就描述了一个段。 给定一个完整的逻辑地址段选择符+段内偏移地址,看段选择符的T1为0还是1,知道当前要转换是GDT中的段,还是LDT中的段,再根据相应寄存器,得到其地址和大小。使用段选择符中的前13位,在这个数组中查找到对应的段描述符,即可得到它的基地址,基地址Base + offset即要转换的线性地址。

7.3 Hello的线性地址到物理地址的变换-页式管理

线性地址即虚拟地址(VA)到物理地址(PA)之间的转换通过分页机制完成,而分页机制是对虚拟地址内存空间进行分页。虚拟地址包含两个部分:VPN(虚拟页号)、VPO(虚拟页面偏移),物理地址由PPN与PPO共同分配组成,MMU利用VPN选择适当的PTE,根据PTE,我们知道虚拟页的信息,如果虚拟页是已缓存的,那直接将页表条目的物理页号和虚拟地址的VPO串联起来就得到一个相应的物理地址。

图7.3.1

7.4 TLB与四级页表支持下的VA到PA的变换

CPU产生虚拟地址VA,虚拟地址VA传送给MMU,MMU使用VPN高位作为TLBT和TLBI,向TLB中寻找匹配。如果命中,则直接得到PA。如果没有命中,MMU查询页表,CR3确定第一级页表的起始地址,VPN1确定在第一级页表中的偏移量,查询出PTE,如果在物理内存且权限符合,确定第二级页表的起始地址,最终将在第四级页表中找到PPN,与VPO组合成PA,并且向TLB中添加条目。

7.5 三级Cache支持下的物理内存访问

CPU发送一条VA,由7.4的操作过程得到PA,由PA中的组索引位CI,在L1cache找对应的组。如果有对应的组,就再比较标志位,匹配成功则检查块的有效位的标志值是否为1,则命中,然后根据偏移量取出需要的数据。否则进入上级cache进行查找,如果有空闲块则将目标块放置到空闲块中,否则将缓存中的某个块驱逐,然后将目标块放到被驱逐块的位置。

7.6 hello进程fork时的内存映射

Shell通过调用fork()函数自动创建一个新的进程,这个进程有新的数据结构,并且内核给他分配了一个唯一的pid。同时有着自己的独立的虚拟内存空间,独立的逻辑控制流,除此以外还有与父进程相同的区域结构、页表等的一份副本,也可以访问任何父进程已经打开的文件。当fork在新进程中返回时,新进程现在的虚拟内存刚好和调用fork时存在的虚拟内存相同,当这两个进程中的任一个后来进行写操作时,写时复制机制就会创建新页面,因此,也就为每个进程保持了私有地址空间。

7.7 hello进程execve时的内存映射

在bash中的进程中执行了如下的execve调用:execve("hello",NULL,NULL);execve函数在当前进程中加载并运行包含在可执行文件hello中的程序,用hello替代当前bash中的程序。删除已存在的用户区域,然后映射私有区域,映射共享区域,为了设置程序计数器,最后要用exceve设置当前进程的上下文中的程序计数器到代码区域的入口点。

7.8 缺页故障与缺页中断处理

如果程序执行过程中发生了缺页故障,则内核会调用缺页处理程序。程序首先会检查虚拟地址是否合法,如果不合法则触发一个段错误,将程序终止。然后检查进程是否有读、写或执行该区域页的权限,如果不具有则触发保护异常,程序终止。两步检查都无误后,内核将选择一个牺牲页,如果该页被修改过则将其交换出去,换入新的页并更新页表。然后将控制转移给hello进程,再次执行触发缺页故障的指令。

7.9动态存储分配管理

(以下格式自行编排,编辑时删除)

Printf会调用malloc,请简述动态内存管理的基本方法与策略。

动态内存管理的基本方法与策略:

动态储存分配管理使用动态内存分配器(如malloc)来进行。动态内存分配器维护着一个进程的虚拟内存区域,称为堆。分配器将堆视为一组不同大小的块的集合。每个块就是一个连续的虚拟内存页,要么是已分配的,要么是空闲的。已分配的块显式地保留为供应用程序使用。空闲块保持空闲,直到它显式地被应用所分配。

一个已分配的块保持已分配的状态,直到它被释放,这种释放要么是应用程序显式执行的,要么是内存分配器自身隐式执行的。动态内存分配主要有两种基本方法与策略:

1.带边界标签的隐式空闲链表分配器管理

对比于显式空闲链表,代表并不直接对空闲块进行链接,而是将对内存空间中的所有块组织成一个大链表,在块的首尾的四个字节分别添加header和footer,负责维护当前块的信息(大小和是否分配)。由于每个块是对齐的,所以每个块的地址低位总是0,可以用该位标注当前块是否已经分配。可以利用header和footer中存放的块大小寻找当前块两侧的邻接块,方便进行空闲块的合并操作。优点是简单,缺点是搜索所需时间与堆中以分配块和空闲块的总数成线性关系。

2.显式空闲链表管理

显式空闲链表是将堆的空闲块组织成一个双向链表,在每个空闲块中,都包含一个前驱与一个后继指针。进行内存管理。在显式空闲链表中。可以采用后进先出的顺序维护链表,将最新释放的块放置在链表的开始处,也可以采用按照地址顺序来维护链表,其中链表中每个块的地址都小于它的后继地址,在这种情况下,释放一个块需要线性时间的搜索来定位合适的前驱。

7.10本章小结

本章介绍了在hello的内存管理,虚拟地址、物理地址、线性地址、逻辑地址的区别以及它们之间的变换模式,以及段式、页式的管理模式,基于内存映射重新认识fork和execve,同时介绍了动态存储分配的方法与原理。

(第7 2分)

第8章 hello的IO管理

8.1 Linux的IO设备管理方法

设备的模型化:Linux将文件所有的I/O设备甚至内核都模型化为文件,所有的输入和输出都能被当做相应文件的读和写来执行。

设备管理:Linux将设备映射为文件,于是便允许Linux内核引出一个简单、低级的应用接口,称为Unix I/O。Linux就是基于Unix I/O实现对设备的管理。

8.2 简述Unix IO接口及其函数

Unix I/O接口:

1.打开文件。一个应用程序通过要求内核打开相应的文件,来宣告它想 要访问一个 I/O 设备

2.shell 创建的每个进程开始时都有三个打开的文件:标准输入(描述符为0)、标准输出(描述符为1)和标准错误(描述符为2)。

3. 改变当前的文件位置。对于每个打开的文件,内核保持着一个文件位置k,初始为0,这个文件位置是从文件开头起始的字节偏移量,应用程序能够通过执行seek,显式地将改变当前文件位置k。

4. 读写文件。一个读操作就是从文件复制n>0个字节到内存,从当前文件位置k开始,然后将k增加到k+n,给定一个大小为m字节的而文件,当k>=m时,触发EOF。类似一个写操作就是从内存中复制n>0个字节到一个文件,从当前文件位置k开始,然后更新k。

5. 关闭文件。当应用完成了对文件的访问之后,它就通知内核关闭这个文件,作为响应,内核释放文件打开时创建的数据结构,并将这个描述符恢复到可用的描述符池中。无论一个进程因为何种原因终止时,内核都会关闭所有打开的文件并释放他们的内存资源。

Unix I/O函数:

1.打开文件:int open(char* filename,int flags,mode_t mode)

Filename:文件名

Flags:文件权限

Mode:指定新文件的访问权限位

返回值:成功则返回文件描述符,失败则返回-1.

2.关闭文件:int close(int fd)

Fd:文件描述符

返回值:成功则返回0,失败则返回-1

3.读文件ssize_t read(int fd,void *buf,size_t n)

Buf:存储要写的数据

n:写入的长度,单位:字节

返回值:成功则返回写入的字节数,失败则返回-1。

4.写文件ssize_t wirte(int fd,const void *buf,size_t n)

Buf:存储要写的数据

n:读出的长度,单位:字节

返回值:成功则返回读出的字节数,失败则返回-1。

8.3 printf的实现分析

首先查看printf函数的函数体:

图8.3.1

然后再看vsprintf:

图8.3.2

vsprintf函数将所有的参数内容格式化之后存入buf,返回格式化数组的长度。write函数将buf中的i个元素写到终端。从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall.字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量),最终打印出字符串。

8.4 getchar的实现分析

异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。

getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。

当用户键入回车之后,getchar才开始从stdio流中每次读入一个字符。getchar函数的返回值是用户输入的第一个字符的ascii码,如出错返回-1,且将用户输入的字符回显到屏幕。如用户在按回车之前输入了不止一个字符,其他字符会保留在键盘缓存区中,等待后续getchar调用读取。也就是说,后续的getchar调用不会等待用户按键,而直接读取缓冲区中的字符,直到缓冲区中的字符读完为后,才等待用户按键。

8.5本章小结

本章介绍了Linux的IO设备管理方法,Unix IO接口及其函数,分析了printf函数和getchar函数的实现。

(第81分)

结论

用计算机系统的语言,逐条总结hello所经历的过程。

你对计算机系统的设计与实现的深切感悟,你的创新理念,如新的设计与实现方法。

在这次大作业中,我们体验了hello的波澜壮阔的一生。

首先将hello.c预处理为hello.i文本文件,再将hello.i编译为hello.s汇编文件,然后再汇编到二进制可重定位目标文件hello.o,hello.o链接生成可执行文件hello,bash进程调用fork函数,生成子进程,execve函数则加载运行当前进程的上下文中加载并运行新程序hello,CPU为hello分配时间片,使hello独享,顺序执行逻辑控制流。存储管理与MMU实现从VA到PA的转换。TLB、多级页表、cache、DRAM内存、动态内存分配器相互协作,共同完成内存的管理。最后再通过linux I/O将hello输入输出与外界交互,最后到达终止。至此,hello度过了它看似简单却又不平凡的一生。

感悟:看似只需一个按钮,一行命令就可以运行的程序,其实是一个相当不简单的设计,这是无数先贤们智慧的结晶,感谢伟大的计算机系统设计师们,他们为我们打开了一个精彩无比的世界!

(结论0分,缺失 -1分,根据内容酌情加分)

附件

列出所有的中间产物的文件名,并予以说明起作用。

文件名

功能

hello.c

源程序

hello.i

预处理后的文件

hello.s

汇编文件

hello.o

可重定位目标执行文件

hello

可执行文件

hello.elf

hello.o的ELF格式

hello.txt

hello.o的反汇编语言

hello1.txt

hello的反汇编语言

hello1.elf

hello的ELF格式

(附件0分,缺失 -1分)

参考文献

为完成本次大作业你翻阅的书籍与网站等

[1]  百度百科关于概念的介绍,比如预处理,ELF等概念。

[2]  深入理解计算机系统原书第3版-文字版.pdf

(参考文献0分,缺失 -1分)

哈工大2022计算机系统大作业---程序人生相关推荐

  1. 【哈工大2022计算机系统大作业“程序人生”】

    计算机系统 大作业 题 目 程序人生-Hello's P2P 专 业 计算机 学 号 120L021504 班 级 2003012 学 生 乔江洋 指 导 教 师 郑贵滨 计算机科学与技术学院 202 ...

  2. 2022计算机系统大作业——程序人生-Hello’s P2P

    计算机系统 大作业 题     目 程序人生-Hello's P2P 专       业 计算机 学    号 120L021716 班    级 2003005 学       生 蔡泽栋 指 导 ...

  3. 哈工大2022年大作业——程序人生

  4. 【2022】哈工大计算机系统大作业——程序人生Hello’s P2P

    2022哈工大计算机系统大作业--程序人生Hello's P2P 摘要 第1章 概述 1.1 Hello简介 1.2 环境与工具 1.3 中间结果 1.4 本章小结 第2章 预处理 2.1 预处理的概 ...

  5. HIT 深入理解计算机系统 大作业 程序人生-Hello’s P2P

    HIT 深入理解计算机系统 大作业 程序人生-Hello's P2P 本论文旨在研究 hello 在 linux 系统下的整个生命周期.结合 CSAPP 课本, 通过 gcc 等工具进行实验,从而将课 ...

  6. 2022哈工大计算机系统大作业——程序人生

    计算机系统 大作业 题     目 程序人生-Hello's P2P 专       业 人工智能(未来技术) 学   号 120L020301 班   级 2036011 学       生 张思远 ...

  7. 哈工大2022秋计算机系统大作业-程序人生(Hello‘s P2P)

    计算机系统 大作业 题     目 程序人生-Hello's P2P 专       业 计算机科学与技术 学    号 班    级 学       生 指 导 教 师 刘宏伟 计算机科学与技术学院 ...

  8. 哈工大2022春计算机系统大作业:程序人生-Hello‘s P2P

    计算机系统 大作业 题     目 程序人生-Hello's P2P 专       业 计算机类 学   号 120L021305 班   级 2003002 学       生 李一凡 指 导 教 ...

  9. 哈工大计算机系统大作业 程序人生-Hello’s P2P 2022

    2022哈工大计算机系统大作业 目录 摘 要 第1章 概述 1.1 Hello简介 1.2 环境与工具 1.3 中间结果 1.4 本章小结 第2章 预处理 2.1 预处理的概念与作用 2.2在Ubun ...

最新文章

  1. java 中启动线程的正确方式
  2. python queue 查询是否在队列中_python队列Queue的详解
  3. java 中调用 Matlab 的函数
  4. mysql列宽设置,mysql – 从.csv文件确定最佳列宽
  5. c++类与类的依赖(Dependency)关系
  6. JFreeChart项目实例
  7. [实验流体力学][Matlab] pi 定理的应用
  8. SDUT-保留整数 -
  9. 使django与数据库保持长连接
  10. 事件驱动和状态机模式在YARN中的使用
  11. 3D图形学矩阵完全解析傻瓜版
  12. 2022企业邮箱登陆入口介绍,企业邮箱电脑版登陆入口有哪些?手机如何登陆企业邮箱?
  13. 技术人最基本投资建议
  14. JAVA怎么对接第三方短信平台?短信验证码完整API文档
  15. 浏览器相关(持续更新)
  16. 嵌入式Linux开发环境搭建(二)
  17. Cris 的Python日记(五):Python 数据结构之元祖,字典和集合
  18. (网管工作日志)Canon 清零
  19. 与其苟延残喘不如纵情燃烧
  20. 推荐系统系列一:推荐系统介绍

热门文章

  1. 站在巨人肩膀上优雅地分蛋糕
  2. 乘风破浪的中国数据库
  3. 多维尺度分析MDS详解
  4. 【超快捷】Windows系统自带的快捷键合集
  5. 万字拆解飞鹤奶粉:4年增收150亿背后的增长策略是什么?
  6. 1.3 欠/过拟合,局部加权回归(Loess/LWR)及Python实现(基于随机梯度下降)
  7. 为什么大数据工程师比Java程序员工资高
  8. 解忧云SMS短信发送系统服务平台源码+解密完美版
  9. 诺基亚CEO埃洛普的2012:煎熬中看到希望
  10. C# 使用SQLite 错误 - 试图加载格式不正确的程序