计算机系统大作业

孤者浪人 提交于 2020-01-04 14:03:39

#计算机系统大作业

题 目 程序人生-Hello’s
P2P

专 业 软件工程

学   号 1183710227

班   级 1837102

学 生 孙兴博

指 导 教 师 史先俊

计算机科学与技术学院

2019年12月

摘 要

摘要是论文内容的高度概括,应具有独立性和自含性,即不阅读论文的全文,就能获得必要的信息。摘要应包括本论文的目的、主要内容、方法、成果及其理论与实际意义。摘要中不宜使用公式、结构式、图表和非公知公用的符号与术语,不标注引用文献编号,同时避免将摘要写成目录式的内容介绍。

论文内容主要是在预处理,编译,汇编,链接,进程管理,存储管理,和io管理等方面,对hello例程进行全面的系统级解释。

文章首先对源文件hello.c文件变为hello可执行文件的中的过程,以及产生的中间文件,来描述关于预处理,编译,汇编和链接的内容。再利用hello可执行文件执行过程中进程切换,内存分配情况和输入输出情况对有关于进程管理,存储时地址的管理,地址的映射和转换,Linux下的io管理方法接口等进行描述。

本文通过hello.c例程,对程序从源代码到可执行文件,再到被载入内存执行的过程,使用计算机系统的相关知识概念,进行解释。

关键词:计算机系统、编译,汇编,链接,进程,内存,shell,信号,cache;

(摘要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的整个过程。

P2P:首先使用高级语言编辑成文本文件,在这里是hello.c文件;然后经过cpp预处理文件,将#include的头文件包含进文件中,将宏进行替换,生成.i文件;交给编译器ccl进行编译,生成.s汇编文件,编译文件经过汇编器as转换为.o二进制可重定位文件,再交给链接器ld进行链接生成.o可执行程序;在shell中输入命令shell,会为之调用fork创建一个独立的进程,再调用execve,执行hello.o程序。

020:刚开始程序是不在内存空间中的,也就是在开始时为0,当在shell中使用execve加载并执行该程序时,操作系统为程序分配一部分虚拟空间,将程序加载到虚拟空间所映射的物理内存空间中,然后执行目标程序。在进程终止后,shell回收hello进程,操作系统会释放进程的虚拟空间、相关数据结构,变为0

1.2 环境与工具

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

软件环境:Windows 10 64位,VMware Workstation
Pro,Ubuntu 18.04 LTS
64位

硬件环境:X64 CPU;1.99GHz ; 8G RAM;1125 GHD Disk

开发工具:gcc++,gdb,code blocks

1.3 中间结果

Hello.c:C语言编写的源代码文件

Hello.i:预编译后的文件

Hello.s:编译后的汇编文件

Hello.o:汇编后的汇编可重定位文件

Hello:链接器处理后生成的可执行文件

c.txt:反汇编代码

a.txt:.o文件的反汇编文件

b.txt:.o文件的显示重定位的反汇编文件

1.4 本章小结

本小节对P2P和020的概念进行了简单的解释,列明了本次大作业的环境和工具,列出了中途生成的所有的辅助文件并解释其作用。

(第1章0.5分)

第2章 预处理

2.1 预处理的概念与作用

概念:预处理器(cpp)根据include指令,修改原始的c程序。得到一个以.i为后缀的预处理文件

作用:将#include所包含的头文件直接加入到文本文件中。

对于一些宏定义,也在预处理阶段进行宏替换。

处理所有的预编译指令

添加行号信息文件名信息,便于调试

删除所有注释

保留所有的#progma编译指令

2.2在Ubuntu下预处理的命令

gcc hello.c -E
-o hello.i

应截图,展示预处理过程!

2.3 Hello的预处理结果解析

经过预处理,生成了hello.i中 在hello.i文件中包含了hello.c的main函数和全局变量sleepsecs,并将#include <stdio.h>#include<unistd.h>#include<stdlib.h>替换为相应的文件,将相应的文件加入到hello.i的文件中。Hello.i文件长度增长,认为可以阅读的文本文件

2.4 本章小结

本节描述了预处理的概念和具体的作用,在虚拟机中也对hello.c进行了实际的预处理,生成了hello.i文件,通过浏览hello.i文件更好的了解预处理的作用

(第2章0.5分)

第3章 编译

3.1 编译的概念与作用

编译:编译器(ccl)将文本文件(预处理文件hello.i)翻译成汇编文本文件(hello.s),用文本格式描述低级及其语言指令

作用:扫描,语法分析,语义分析,源代码优化,目标代码生成,目标代码优化;

生成汇编代码

汇总符号

生成.s文件

3.2 在Ubuntu下编译的命令

Gcc -S hello.i -o hello.s

内容:

3.3 Hello的编译结果解析

1数据:

常量:以十进制数字的形式保存

全局变量:int sleepsecs

在汇编文件中使用sleepsecs(%rib)进行引用,在文件的开头,就为其赋初值,由于是int型,对小数部分舍去,赋初值为2.被存放在。Rodata节中

Main

函数名

局部变量:

Int I 存储在-4(%rbp),并未赋初值,使用movl
$0 , -4(%rbp)语句,为i赋初值为0;

Int argc

存储在edi寄存器中,然后将其放在-20(%rbp)中

Char ** argv
存储在rsi寄存器中,然后将其放置在-32(%rbp)中

2类型转换

对于sleepsecs存在2次类型转换

第一次是在赋初值时,将double类型的常数舍去小数赋值给sleepsecs

第二次是在作为sleep函数的参数时,将其做转为无符号整形,传给sleep函数

3算数运算

++:通过addl $1,-4(%rbp)实现对int型变量i加1,并将结果存储在i中的操作

4逻辑位操作

未使用该操作

5关系操作

Argc!=3:通过cmpl $3,-20(%rbp)对argc和3进行比较,设置状态位,再用je.Le语句如果b==a则跳转,否则不跳转继续往下执行

I<10:开始时对i赋初值为0,然后依次使用addl $1,-4(%rbp)将i增大,使用语句cmpl $7,-4(%rbp)实现i和7的比较,设置状态位,在使用语句jle.L4如果i<=9则继续循环,否则跳出循环

6.数组、指针、结构

指针:argv是二级指针,指向的元素是一级指针

字符串也是用指针的形式进行使用

数组argv[]是一个数组,引用通过对argv的地址加上偏移量得到元素的首地址

7控制转移

If:使用je.L2进行转移判断,如果条件成立,跳转到.L2处,否则顺序执行

For:在循环开始时,给i赋初值为0,然后跳转到.L3处进行比较,使用jle.L4进行转移判断,如果条件成立,跳转到.L2处,否则顺序执行

8函数操作

Main函数:参数传递,%edi存储着argc的值(参数变量的个数),为第一个参数%rsi存储argv的值,作为地址,指向参数字符串数组的首地址为第二个参数;函数调用,主函数,第一个执行的函数;函数返回,返回0

Printf函数:参数传递,%rdi中存储传递的第一个参数,如果要输出字符串,字符串在开头.LC0和.LC1处,将字符串的地址赋值给%rdi作为第一个参数,在第二个printf中有三个参数,另外两个参数通过%rax赋值给%rsi和%rdx;函数调用使用call指令调用;函数返回,将返回值存储在%rax中,使用指令ret返回

Exit函数:参数传递,将1放在%edi中作为参数传递;函数调用,使用call指令进行调用;函数返回,无返回

Sleep函数:参数传递,将sleepsecs的值作为参数,将%eax赋值给%edi,%edi中的值作为第一个参数;函数调用,使用call指令进行调用;函数返回将返回值存储在%eax,使用ret指令返回。

3.4 本章小结

本节,对汇编的概念和作用进行了阐述,对汇编代码进行了分析和解释,并与C语言中的语句进行对比,生成了hello.s文件

(第3章2分)

第4章 汇编

4.1 汇编的概念与作用

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

作用:根据汇编指令和特定的平台,把汇编指令翻译成机器代码;合并各个节,合并符号表,生成.o文件

4.2 在Ubuntu下汇编的命令

Gcc -c
hello.s -o hello.o

反汇编为文本文件后(-D)

4.3 可重定位目标elf格式

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

ELF头:文件格式

.text:已经编译程序的机器代码

.rodata:只读数据

.data:初始化的全局和静态变量

.bss:未初始化的全局和静态变量

.symtab:符号表

.rel.text:一个.text节中位置的列表

.rel.data:别模块引用或定义的所有全局变量和重定位信息

.debug:调试符号表

.line:行号与.text的机器指令之间的映射

.strtab:一个字符串表

符号表中有hello.o中定义和引用的函数和全局变量,信息,其中包含大小、类型、名字等信息

4.4 Hello.o的结果解析

objdump -d
-r hello.o 分析hello.o的反汇编,并请与第3章的 hello.s进行对照分析。

说明机器语言的构成,与汇编语言的映射关系。特别是机器语言中的操作数与汇编语言不一致,特别是分支转移函数调用等。

在源代码的机器及指令中加入了重定位的信息,包括类型和相对位置等,在连接时要修改他们的位置。

机器识别由操作码和操作数组成的机器语言

机器语言和汇编语言是一对一的映射关系

机器语言的跳转对函数的引用是使用与头部的偏移量来表示位置的,在汇编代码中使用的是一个一个的标号表示的

机器语言中的操作数使用的是十六进制格式,汇编语言使用的是十进制

机器语言的反汇编代码为每条语句都加上了具体的地址

机器语言中,全局变量的访问采用短名称+%rip的方式

4.5 本章小结

本节对汇编和汇编后产生的可重定位文件进行了描述,分析了可重定位文件的结构和各个组成部分,各组成部分的内容和作用;比较了机器语言和汇编代码的不同和关系,生成了hello.o可重定位文件

(第4章1分)

第5章 链接

5.1 链接的概念与作用

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

概念:链接器(ld)将文件hello.o中的一些未定义的变量,函数,与其所在的.o文件进行合并,生成可执行文件hello

作用:合并各个.obj文件的节合并符号表,进行符号解析;进行符号地址的重定位;生成可执行文件

5.2 在Ubuntu下链接的命令

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

使用ld的链接命令,应截图,展示汇编过程! 注意不只连接hello.o文件

Gcc hello.o
-o hello

5.3 可执行目标文件hello的格式

分析hello的ELF格式,用readelf等列出其各段的基本信息,包括各段的起始地址,大小等信息。

共有29个节头,初始偏移量0x1a08

5.4 hello的虚拟地址空间

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

由程序头可知,hello各个段的虚拟地址空间地址和大小,如代码的虚拟地址为0x0大小为0x212

5.5 链接的重定位过程分析

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

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

在hello程序中,程序的起始不再是0,是一个虚拟地址;

一些库函数和外部调用函数都在文件中表述出来,引用是直接饮用,使用虚拟地址,均被包括到文件中,不是使用hello.o的间接引用

并且添加了一些其他的节如.init .plt等

链接过程:链接器为可重定位文件分配虚拟空间地址,进行重定位,然后按照符号表,把每个符号定义个内存位置联系起来,然后修改对这个扶摇的引用,让他们都指向这块内存,从而生成可执行程序

重定位:链接器将所有相同类型的节合并为一个节,然后链接器将运行时内存地址付给新的节和输入模块定义的每个符号,然后链接器利用可重定位条目,修改代码节和数据节中对符号的引用

5.6 hello的执行流程

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

_dl_start_user

_dl_init

_start

_libc_start_main

_cxa_atexit

_libc_csu_init

_init

_setjmp

_sigsetjmp

_sigjmp_save

main

(main后)

puts@plt

exit@plt

_dl_runtime_resolve_xsave

_dl_fixup

_dl_lookup_symbol_x

exit

5.7 Hello的动态链接分析

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

通过查找得知_dl_init在00007fa8:91476630位置,在执行_dl_int函数前

在执行完函数后,global_offset表由全0状态被赋值为相应的值

5.8 本章小结

本节讨论了链接的过程,对hello.o文件的链接和执行过程进行了分析,对链接生成的可执行程序也进行了分析,链接使我们可以将文件分解成若干个小块进行设计,是的程序设计更加高效有序。链接分为静态链接和动态链接,两者各有利弊,静态链接每次更稀释都系需要重新编译,但是可以有效防止其他人的恶意攻击;动态链接大大节省了内存空间,并且更新代码无需重新连接比较便利

链接实现了多个文件的合并,最终生成一个完整的可执行的程序

(第5章1分)

第6章 hello进程管理

6.1 进程的概念与作用

进程是程序执行的一个实例,是计算机中的程序关于数据上的一次运行活动

作用:进程概念的建立,让计算机系统可以更好的管理不同程序的运行情况,方便上下文的切换,提供一个独立的虚拟空间给每个进程,表现出他们在独占内存和cpu的假象,产生并行的现象

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

作用:提供用户与操作系统交互的界面,用户通过这个界面访问操作系统内核的服务,可以输入命令,执行指令

处理流程:

读取输入的命令行;shell首先从命令行中找到特殊字符,将该字符翻译为间隔符号,将命令行分割为小块的tokens;程序块tokens处理,检查是否为shell中引用的关键字;当程序块tokens被确定以后,shell根据aliases文件中的列表来检查命令的第一个单词,如果这个单词在其中,那么执行替换操作,并且处理回到第二部分重新分割程序块tokens;shell对符号~进行替换;shel对所有符号的变量进行替换;shell将命令行的内嵌命令表达式替换为命令;shell计算采用标记的算数表达式;shell根据栏位分割符号,重新划分为块tokens;shell执行通配符的替换;shell将所有处理结果中用到的注释删除,并进行命令检查(内建命令,shell函数,可执行的脚本);在执行前的最后一步是初始化所有的输入输出重定向;执行命令

6.3 Hello的fork进程创建过程

在命令行中输入./hello指令,shell处理指令,作为可执行脚本程序,使用fork创建一个子进程,执行hello程序

6.4 Hello的execve过程

Execve函数加载并运行可执行文件,将hello加载到当前的进程中,将原先程序覆盖,释放掉原先程序的用户控件,加载hello程序到用户空间中,hello程序和源程序的进程相同,具有相同的PID。Execve加载了可执行程序的名字hello后调用启动代码,启动代码设置栈,将控制传递给hello的主函数

6.5 Hello的进程执行

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

1上下文信息:执行进程所需要的信息

2进程时间片:每个进程都在不同的时间段内运行,每个进程占用CPU的时间段

3用户态与核心态的转换:可以通过中断,陷阱,故障,终止等异常情况,程序会从用户态转换到内核态,内核保存进程的上下文,恢复下一个进程的上下文来重新启动该进程,控制转交给进程,从核心态转换到用户态

4.hello的进程调度过程:限制性hello程序,进程在用户态,控制暂时在hello的进程中,当输入的参数数量不是3时,会调用exit函数结束进程,shell回收hello进程;当输入的参数数量为3时,会进入循环调用sleep函数,进程休眠一段时间,在这段时间内控制可能会交给内核,内核保存上下文,保包括I,sleepsecs的值,寄存器,栈,pc,条件码,state等值,然后恢复要进入进程的上下文,最后将控制传递给该进程,并开始计时,在休眠时间足够后,sleep会传送一个信号,可能会调用中断信号处理函数,将控制传递给内核,内核保存当前进程的上下文,恢复hello进程的上下文,将控制传递给hello进程,继续执行hello

6.6 hello的异常与信号处理

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

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

1异常种类:终止异常,exit函数,Ctrl—c会产生中职信号,终止程序;中断异常:Ctrl-z;陷阱异常:sleep函数会触发;

2信号:SIGINT:Ctrl-Z会产生这个信号,会中断进程,切换到别的进程中;

SIGCONT:使用fg命令,会向进程发送该信号,切换到该进程继续执行(如果停止了).

SIGTRAP:sleep函数会触发这个信号,调用陷阱异常处理程序,并跟踪陷阱.

SIGCHLD:exit函数会发送这个信号,终止进程.

kill可以给根据PID给进程发送信号.

6.7本章小结

本节中介绍了进程异常信号的概念,对一场控制流的概念作了解释,并介绍了核心态和用户态两种模式,分析了进程的创建,程序的运行,上下文的切换,并发程序的机理,简要描述了一些异常,信号和其处理函数,描述了一些命令行的作用和shell工作简单原理。

(第6章1分)

第7章 hello的存储管理

7.1 hello的存储器地址空间

结合hello说明逻辑地址、线性地址、虚拟地址、物理地址的概念。

逻辑地址:是指由程序产生的和段相关的偏移地址(出现再机器语言中).由一个标识符加上一个指定段内的相对地址的偏移量,是cpu执行程序中的一种中间地址.hello.o反汇编的输出文件中的地址就是逻辑地址.

线性地址:逻辑地址到物理地址变换之间的中间层.逻辑地址加上相应段的基地址就生成了线性地址

虚拟地址:虚拟地址是一个抽象的概念空间,每一个虚拟地址对应与一个虚拟页,每一个虚拟页会映射一个磁盘空间的一页,如果要使用该数据,则会将该页载入内存,这样每个虚拟地址就对应与唯一的一个物理地址.

物理地址:指出目前CPU外部地址总线上的寻址物理内存的地址信号,用于内存级芯片的单元寻址.可以将内存看成一个从0字节开始的大数组,数组中每个字节拥有独有的物理地址.

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

逻辑地址是程序产生的和段相关二点偏移地址,需要转换成线性地址,才能经过MMU转换成物理地址才能访问;

一个逻辑地址由2部分组成,段标识符:段内偏移量.段标识符由一个16位长的字段组成,成为段选择符.其中前13位是一个索引号.后面3位包含一些硬件细节.

索引号(13位) T1 RPL

虚拟内存被分成了很多个,这些段组成了一个”数组”,叫做段描述符表,一个地址,通过段标识符的前13位,直接再段描述符中找到一个具体的段描述符,这个迷哦书符描述了一个段,包括了数据描述符,代码描述符和系统描述符,每一个段描述符由8个字节组成,其中包括Base字段,他描述了一个段的开始位置的线性地址. intel在设计时,一些全局的段描述符,放在全局段描述符表(GDT)中,局部的就放在局部段描述符表(LDT)中,用段选择符中T1字段表示,T1=0,表示用GDT;T1=1表示用LDT. LDT和GDT的地址和大小分别放在ldtr寄存器和gdtr寄存器中.

   获得一个逻辑地址后,首先获取前16位段标识符,看T1字节是否为1,再从gdtr或ldtr中取出GDT和LDT的地址和大小,然后得到段标识符的前13位,加上1.中得到的GDT或LDT的地址,知道逻辑地对应段的段描述符的地址,然后,根据段描述符的地址取得段描述符,并获得,Bass信息,知道段得基地址,最后将基地址加上段内偏移量得到线性地址

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

多个连续的虚拟地址会组成一个页,每个已分配的虚拟页会映射一个磁盘页,如果这个磁盘页被加载到内存中,那么这个虚拟页中的每个虚拟地址都会对应一个内存中的物理地址,虚拟页对内存页或磁盘页的映射是使用页表的方式存储的。每个虚拟地址的前n-p位标识他的虚拟页号,后p位标识偏移量,每个虚拟页都会有一个页表项使用vpn作为银锁,表的基地址存储在寄存器中,作为进程上下文的一部分,通过基地址+索引就可以找到虚拟页对应的页表项.PTE由 有效位:PPN 组成,对于已分配的虚拟页,当有效位为1是,虚拟也对应的页在内存中,PPN表示虚拟页对应的物理页的页号;有效位为0时,虚拟页不再内存,VPN表示虚拟页对应磁盘页的地址. 在现代计算机中,采用多级页表的形式储存.将VPN分给成多个部分,每个部分对应与某级页表的索引值.第一级页表的基地址储存在寄存器中,作为上下文的一部分,VPN的前a1位标识这个页表的索引,其中存储着相对应的二级页的基地址,VPN接着a2位标识二级页表的索引,依次下去,知道最后一级页表,可以从中取出虚拟地址对应的 有效位:PPN得到虚拟地址的前n-p位VPN通过VPN获得相应的PTE如果PTE有效位为1,则获得其PPN;如果为0,则调用缺页处理程序,将相应页载入到内存中,获得其PPN通过PPN知道对应物理页的首地址+虚拟地址的后p位(VPO),得到物理地址

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

TLB是MMU中对与PTE的缓存,采用组相联的方式;

TLB由TLB标记,PTE虚拟地址被划分位:a1位 a2位 a3位 a4位

MMU先在TLB中寻找PTE;根据虚拟地址的后p+t-1位值作为组号,找到其对应的TLB的组,VPN剩下的位作为标记,与该组中的标记进行对比,如果存在标记相同切有效为为1的pte那么获得pte中的ppn如果不存在,那么将vpn发送给内存和cache。通过一个固定寄存器中的值获得以及页表的基地址,由a1位值作为索引,知道对应表中的值,将其作为二级页表的机制,由a2位值作为索引,直到有a4作为索引获得四级页表的pte的值,这样就可以得到vpn所对应的ppn的值,再由ppn+vpo就可以得到va对应的pa

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

通过内存地址的组索引获得值,如果对应的值是data则像L1 d-cache对应组中查找,如果是指令,则向L1 i-cache对应组中查找。将L1对应组中的每一行的标记位进行对比,如果相同并且有效位为1则命中,获得偏移量,取出相应字节,否则不命中,向下一级cache寻找,直到向内存中寻找

7.6 hello进程fork时的内存映射

内存映射为每个进程都创建独立得虚拟地址空间.当fork函数被当前进程调用时,内核位新进程创建各种数据结构,并分配给他一个唯一得PID.通过创建进程得mm_struct,区域结构和页表得原样副本,他将2个进程中得每个页面都标记为只读,并将2个进程中得每个区域结构都标记为写时复制. fork在新进程中返回时,新进程现在得虚拟内存刚好和调用fork时存在得虚拟空间内存相同.当2个进程中,有一个要对其中得私有部分进行写操作时,会触发只读得保护,会触发故障处理程序,将要写得页复制一份,并恢复他写得权限,回到原来程序得当前指令,进行写操作.对于共享得部分,不同进程得不同虚拟页会映射到同一个内存物理页.

7.7 hello进程execve时的内存映射

1.删除已存在的用户区域. 删除当前继承虚拟地址的用户部分中的已存在的区域结构

2.映射私有区域. 为新程序的代码,数据,bss和站区域创建新的区域结构.所有这些新的区域都是私有的,写时复制的.代码和数据区域被映射为hello.out文件中的.text和.data取. bss区域时请求二进制零的.

3.映射共享区域. 如果hello.out程序与共享对象(或目标)链接,比如标准c库 libc.so, 那么这些对象都是动态链接这个程序的, 然后再映射到用户虚拟地址空间中的共享区域内.

4.设置程序计数器(PC). execve做的最后一件事就是设置当前进程上下文中的程序计数器,使之指向代码区域的入口点.

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

1.缺页:将DRAM的缓存不命中成为缺页

2.缺页故障:当cpu引用的虚拟地址所在的虚拟页的PTE有效位为0,即所对应的虚拟页不再内存,会引发缺页故障异常.

3.缺页中断处理: 缺页异常调用内核的缺页异常处理程序.程序选择内存中的一个页作为牺牲页,如果这个页被修改过(修改位被设置),则将该页写回磁盘;然后按照目标虚拟页的PTE的磁盘地址,将磁盘的页取出放内存中,同时修改PTE. 然后返回程序中断处的当前指令,继续请求访问该虚拟地址.

7.9动态存储分配管理

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

动态内存通过动态内存分配器进行管理.

动态内存分配器维护着一个进程的虚拟内存区域,称为堆.系统之间细节不同,但是不是共通性. 假设堆使一个请求二进制零的区域,他紧接再未初始化的数据区域后开始, 并向更高地址处生长. 对于每一个进程,内核维护一个边量brk作为堆的顶部;

分配器将堆视为一组不同大小的块的集合来维护. 每个块都是一个连续的虚拟内存片,要么是已分配的,要么是空闲的. 已分配的块显示地保留,供应用程序使用,空闲块可用来分配. 空闲块保持空闲,知道他显示地被应用所分配. 一个已分配的块保持已分配的状态,直到他被释放,这种释放要么是应用程序显示的执行,要么是内存分配器自身隐式执行的.

基本方法:

隐式空闲链表: 每个块包含一个4字的头部和4字的相同信息的尾部,分别再块的开始和结尾,其中存储了块的大小和块的分配位.(如果式双子对齐,后3位储存分配位),分配位为1则表示该块已分配;位0则表示该块式空闲的. 每次寻找会根据的堆的头部分配位判断是否是空闲的,大小值判断是否适合存储,并根据大小信息找到一个块的块头. 尾部则是在空闲块合并时,提供前一个块的大小和是否位空闲块的信息.

显示空闲链表:再空闲块中,除了头部和尾部,还存在指向前一个空闲块和后一个空闲块的2个指针,通过指针可以找到所有的空闲块

策略

首次分配:每一次分配,都从堆的开始寻找空闲块,直到找到一个可以存储的下的空闲块,就分配该块.

下次分配:每次分配都从上次的地方开始寻找空闲块,一旦找到可以存储的下的空间块,就分配该块.

最佳分配:遍历所有的空闲块,找到可以存储的下,且最小的块进行分配

所有的分配中,如果找不到合适的块,就会调用extend函数,扩大堆,增大brk

7.10本章小结

本小节讨论了存储空间的管理,首先解释了四种地址的概念,逻辑地址、线性地址、虚拟地址、物理地址,接着描述了逻辑地址到线性地址再到物理地址的转换过程。再用TLB和四级页表的实例描述了va到pa的转变过程,说明了如何使用物理内存访问cache。在将进程使用到的fork和execve的内存映射情况加以描述

(第7章 2分)

第8章 hello的IO管理

8.1 Linux的IO设备管理方法

设备的模型化:文件

设备管理:unix io接口

i/o接口:1打开文件:一个应用程序通过要求内核打开相应的文件,告知想要访问一个i/o设备。内核返回一个非负整数(描述符),他在后续对此文件的所有操作中标识这个文件,内核记录这个文件所有的信息2shell闯进的每个进程开始时都有三个文件打开:标准输入,标准输出和标准错误3改变当前文件位置:对于每个打开的文件,内核保持着一个文件位置k,初始为0,这个文件位置是从文件开头起始的字节偏移量,应用程序可以通过seek操作设置k的值4读写文件:一个读操作就是从文件复制n>0个字节到内存中,从当前文件位置k开始,然后将k增加到k+n。给定一个大小为m字节的文件,当k>=m时执行读操作会触发一个成为EOF的条件5关闭文件:当应用完成了对文件的访问之后,他就通知内核关闭这个文件作为相应,内核释放文件打开时创建的数据结构,并将这个描述符恢复到可用的描述符池中。无论一个进程因为什么原因终止时,内核都会关闭所有的文件并释放他们的内存资源

8.2 简述Unix
IO接口及其函数

1open函数将filename转换为一个文件描述符,并返回描述符数字,

2close关闭一个打开了的文件

3read,fscanf用来对文件输入

4write,fprintf用来对文件输出

5RIO包中存在一些带缓存的读取输出的函数

8.3 printf的实现分析

https://www.cnblogs.com/pianist/p/3315801.html

从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall.

字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。

显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。

8.4 getchar的实现分析

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

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

8.5本章小结

本小节关于io管理,首先说明了Linux通过io文件化,来很好的统一管理io。接着具体描述了一些i/o接口和函数;最后对两个常见函数printf和getchar的实现进行了具体的分析

(第8章1分)

结论

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

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

一个程序通过预处理,编译,汇编,链接最终形成可执行程序,在进程中使用shell的框架进行辅助交互,采用层级内存管理,使得内存的使用更加高效,i/o管理让文件操作更加有序规律

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

附件

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

Hello.c:C语言源程序代码

Hello.i:预编译后的预编译文件

Hello.s:编译器编译后的编译文件

Hello.o:汇编器处理后的可重定位文件

Hello:链接器处理后的可执行文件

a.
Txt:hello.o的反汇编文件

b.
Txt:hello.o的显示重定位信息的文件

c.
Txt:hello的反汇编文件

(附件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分)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!