哈尔滨工业大学2023春计算机系统大作业

计算机系统

大作业

题     目  程序人生-Hello’s P2P 

专       业        网络空间安全     

学     号        2021110978       

班     级          2103901        

学       生           张森豪        

指 导 教 师             吴锐         

计算机科学与技术学院

2023年4月

摘  要

    根据hello的自白与csapp所学内容对一个hello.c程序完成一个完整的从无到有的运行过程,体验x86-64计算机系统在完成一个简单c语言程序的主要工作机制与流程。

关键词:编译;汇编;链接;存储管理….

(摘要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源代码hello.c文件,然后经过ccl的编译,as的汇编得到hello.s,通过ld将其与一些库链接生成hello可执行文件;最后在shell中输入./hello,shell即会调用fork()执行一个execve()来运行进程。

020:执行hello可执行文件后,shell通过execve将其相关信息加载到虚拟内存中,随后被载入物理内存,然后进入main函数开始执行代码,在执行结束后,父进程对其进行回收,最后shell又回归原始状态。

1.2 环境与工具

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

Windows11

Vmware 16,Ubuntun 20.04

调试工具:

Codeblock 64位,VS2022

1.3 中间结果

列出你为编写本论文,生成的中间结果文件的名字,文件的作用等。

Hello.c 源程序

Hello.i 预处理后的文件

Hello.s 编译后的文件

Hello.o 可重定位目标文件

Hello 可执行目标文件

Helloo.elf hello.o的ELF格式,分析as和链接器的行为

Hello.txt hello.o的反汇编代码

1.4 本章小结

第一章主要解释了hello程序的P2P以及020,以及列出了运行环境以及整个实验中出现的各种文件。

(第1章0.5分)

第2章 预处理

2.1 预处理的概念与作用

1.程序的预处理过程就是将预处理指令(例如#开头的指令)转换为实际代码中的内容(替换)

作用:

(1)在预处理阶段,预处理器(cpp)根据以字符#开头的命令,修改原始的C程序,将用#include形式声明的文件复制到新的程序中。

(2)在预处理阶段,预处理器将程序中间出现的所有的宏名称全部用宏定义当中的字符串进行代换(#define定义的字符串)。

(3)根据#if后面的条件去编译相应的程序部分。

(4)删除所有的注释。

2.2在Ubuntu下预处理的命令

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

在终端内输入命令gcc -E -o hello.i hello.c,得到hello.c的预处理结果。并且将结果保存到hello.i文件内。

2.3 Hello的预处理结果解析

对比源文件,发现预处理指令被拓展为上千行,都是hello.c所涉及到的额所有头文件的信息。

然后就是这些头文件中用typedef所定义的类型别名

    再后面就是include头文件的主体部分,内涵大量的函数声明以及很多的struct内容。

最下面的就是hello.c的原本内容,都是被预处理改变了小部分

2.4 本章小结

本章我们对hello.c文件进行了一个预处理环节,并且根据预处理得到的文件对预处理的过程有了更加明确的认识。预处理会对源代码进行大量展开工作,预处理后的结果任然还是一个c语言的文件。从预处理的这样一个过程我们就会发现原来一个简单的hello.c的背后还有如此一个庞大的内容。

(第2章0.5分)

第3章 编译

3.1 编译的概念与作用

注意:这儿的编译是指从 .i 到 .s 即预处理后的文件到生成汇编语言程序

编译:1、首先会分析语法,对编译完成的程序进行语法分析检测,不符合规范则发送错误,编译器会将原始的C语言语法格式的代码转换为面向CPU的机器指令,转换后的结果以汇编语言的文本形式保存;2、编译器可以产生一种优化的中间代码,可以提高程序性能以及编译器的运行效率。

3.2 在Ubuntu下编译的命令

输入命令gcc -S hello.i -o hello.s -fno-PIC -no-pie -m64得到文件hello.s

应截图,展示编译过程!

3.3 Hello的编译结果解析

此部分是重点,说明编译器是怎么处理C语言的各个数据类型以及各类操作的。应分3.3.1~ 3.3.x等按照类型和操作进行分析,只要hello.s中出现的属于大作业PPT中P4给出的参考C数据与操作,都应解析

3.3.1 汇编初始部分

再本段中可以看到许多声明

.flie              声明源文件”hello.c”

.text             代码节

.section.rodata           只读代码段

.align           声明对指令或数据的存放地址

.string          字符串的声明

.global         全局变量

.type            声明符号类型

3.3.2 数据

a.字符串

      程序中有两个字符串放在只读数据中,分别是.LC0和.LC1

      这里分别对应了源程序中的两个printf中的内容。

b.局部变量

      就是在main函数中定义的一个int i,对应下图。

c.立即数厂里

hello.c中还有一些数字被叫做立即数,而这些立即数不需要经过算术单元计算,表现为”$+数字”的形式,在编译过程中也产生了许多的立即数

 

3.3.3赋值

大部分的赋值函数都是通过Mov指令完成的,比如上图中的movl $0,%eax

3.3.4关系操作

对于关系的判断,通常都是利用test或cmp类指令完成的,例如

3.3.5算术运算

汇编治疗中有大量如add和sub类的指令完成运算

3.3.6数组/指针操作

在hello.c中,同样存在着数组,例如argv[]传递指针到main()中,对于数组的访问操作,通过寄存器中存储的地址加上相应的偏移量字节大小实现。

记录数组首地址

访问数组中的值。

3.3.7控制转移

在hello.c中有关if语句的指令,在Hello.s中都是通过jump指令实现的

3.3.8函数操作

在hello.c中关于printf类的指令实际上是引用了其他库中的函数,所以会调用printf这样的函数,初次之外,还通过call指令调用了多个其他函数

    3.3.9类型转换

    Atoi函数就是将字符串转换为sleep函数所需要的整形参数的过程。

3.4 本章小结

本章中结合hello.c的中数据和类型,对汇编代码中的实现方式进行了分析,介绍了编译器对c语言中各种数据类型的操作。

(第32分)

第4章 汇编

4.1 汇编的概念与作用

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

作用:将汇编代码转变成机器可以执行的命令,每一句汇编语句几乎都对应一条机器指令。

注意:这儿的汇编是指从 .s 到 .o 即编译后的文件到生成机器语言二进制程序的过程。

4.2 在Ubuntu下汇编的命令

       输入指令gcc -c -o hello.o hello.s

      

应截图,展示汇编过程!

4.3 可重定位目标elf格式

       使用readelf -a hello.o > helloo.elf

  1. ELF头

ELF头以一个16字节的序列开始,这个序列描述了生成该文件的系统的字的大小和字节顺序。剩下的部分则包含帮助链接器语法分析和解释目标文件的信息。

  1. 节头

节头部表中包含有节的名称,类型,地址,偏移量以及对齐信息等

  1. 重定位节

重定位节包含有偏移地址、基址信息、链接器识别修改类型、重定位目标的名称等,这些信息将帮助链接器在后续将目标文件合并成可执行文件时的修改引用的操作。

  1. 符号表

每个可重定位模块均有一个符号表,其包含m定义和引用的的符号的信息,其不包含对应于本地非静态程序变量的任意符号。

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

4.4 Hello.o的结果解析

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

首先,不难发现,在hello.s中,汇编使用的操作数均为10进制数,而在hello.o的反汇编中变成了16进制数

    其次,hello.s中,不同的跳转被分为各部相同的段,跳转时通过段名来进行跳转,但是在hello.o的反汇编中,所有的跳转均以相对地址偏移来代替,每个操作都有对应的地址,跳转指令根据地址进行跳转

   

    最后,函数的调用也不同,在hello.s中,函数调用后直接使用了相对应的函数名称,但是在hello.o的反汇编中,函数调用给出的地址是下一条地址,这是以为需要调用的函数最终需要动态链接器才能和确定函数的运行时的执行地址。在机器语言中,对于这些不确定地址的函数的调用时,其调用指令后的相对地址全部设置为0,等待静态链接的确定。

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

最后发现,每一条指令还增加了一个十六进制的表示,即改指令的机器语言,利于,在hello.s中的一个cmpl指令表示:

而在反汇编文件中,该指令变成了:

4.5 本章小结

在本章中,介绍了hello从hello.s到hello.o的整个汇编过程,解析了ELF文件,还对hello.o进行了反汇编,使我了解了从.s到.o过程中产生的一些变化以及相关原因。

(第41分)

第5章 链接

5.1 链接的概念与作用

概念:链接是将各种代码和数据片段收集并组合成一个单一文件的过程,最终这个文件可被加载到内存并被执行。

作用:将程序调用的函数所在的目标文件以某种方式合并到hello.o程序中,最终得到hello文件,它是一个可执行目标文件。

注意:这儿的链接是指从 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

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

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

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

       输入readelf -a hello

ELF头部入下:

节头部表:

       对hello中所有的节信息进行了声明,描述了各个节的大小,偏移量和其他属性

       程序头:

       程序头主要描述了磁盘上的可执行文件的内存布局和如何映射到内存上的。

段节:

       段节的作用是罗列各个节在段中分布情况。

             

       动态节:

       动态节是动态段的核心部分

             

       可重定位条目:

       包含偏移地址,基址信息,链接器识别修改类型,重定位目标名称等信息

       符号表:

      

    版本信息

   

5.4 hello的虚拟地址空间

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

      

       使用edb打开hello从DataDump窗口观察hello加载到虚拟内存的情况,观察到起始的虚拟辞职为00000000:00401000,与hello的ELF文件中节头部表中的init节虚拟地址相同

       借助edb中的Plugins中的SymbolViewer功能,可以看到hello的各结点的起始地址,同样这里也可以看到init的起始地址是0x401000

 

5.5 链接的重定位过程分析

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

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

输入指令,生成反汇编文件

再次通过将该文件与hello.o的反汇编文件对比,可以发现:

  1. 函数变化:

在hello反汇编文件中,链接器将hello.c中所要用到的库函数,例如printf等位置加入到了文件中。

  1. 地址变化:

现在je,call等指令后面的地址都被修改为了绝对虚拟地址:

计算机通过链接器实现链接的过程,在链接其对符号引用进行解析的时候,会将每个引用与它输入的可重定位目标文件的符号表中的一个确定的符号定义关联起来。对那些和引用定义在相同模块的局部符号的引用,符号解析是非常简单明了的,因为在先前的处理中编译器只允许每个模块中的每个局部符号有一个定义。对于全局符号,链接器则会按照编译器事先生成的链接器符号表在其所有的输入模块中寻找相应的定义。如果找不到的话,最终会输出一条错误信息并终止。

而对其重定位的过程分由两步组成:

(a)重定位节和符号定义

链接器对于hello.o中的所有相同类型的节合并为同一类型的聚合节,使得程序中的每条指令和全局变量都有唯一的运行时的内存地址了,因而,在hello的反汇编中的相对地址被虚拟地址所代替。

(b)重定位节的符号引用:

链接器借助汇编器事先生成的重定位条目,修改代码节和数据节对每个符号的引用,使得他们指向正确的运行时地址。因此,相较于hello.o的反汇编,hello的反汇编中的call指令能够指向所调用的函数的虚拟地址。

5.6 hello的执行流程

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

使用edb执行hello,首先,最初的地址时在0x7f89ff0802b0,这里是hello使用动态链接库ld-2.31.so的入口点_dl_start:

然后,程序会跳转到_dl_init,在一系列初始化之后,跳转到hello的程序入口点_start:

执行过程:

  1. hello.out!_init
  2. hello.out_main
  3. hello,out!puts@_plt
  4. hello.out!exit@_plt
  5. hello.out!printf@_plt

6.   hello.out!atoi@_plt

7.  hello.out!sleep@_plt

8.  hello.out!getchar@_plt

9.  libc-2.27.so!exit

5.7 Hello的动态链接分析

 

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

在ELF的头部节表中可以找到.got.plt的虚拟地址

随后使用edb,可以看到在程序未运行时,虚拟地址对于的存储内容

而运行之后,可以发现该位置发生了变化

这样就了解了动态链接的过程,由此可以看出,动态链接器在程序加载的时候解析调用的共享库函数,并使用PLT和GOT来实现函数的动态链接,在解析过程中,GOT中用来存放函数目标地址,PLT使用GOT中存储的地址跳到目标函数。

5.8 本章小结

本章中生成了hello的可执行文件,并且理解了链接的过程以及这个过程中的虚拟地址的分配情况,加深了对重定位,动态链接的理解。

(第51分)

第6章 hello进程管理

6.1 进程的概念与作用

进程是程序在执行中的一个实例,系统的每个程序都运行在某个进程的上下文中。上下文是由程序运行时的一些状态组成的,这些状态包括存放在内存里的程序的代码、数据、栈、寄存器、所占用的资源等。进程这一机制使得每个程序都似乎独占CPU和内存,但实际上同一时刻可能有很多进程在逻辑上并发运行,这是现代多任务操作系统的基础。

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

作用:Shell是用户与操作系统间交互的接口,它为用户提供命令行界面,使用户可以在这个界面输入shell命令,使得计算机能够执行相应的程序,从而完成用户与计算机的交互使得能够按照用户的想法操纵计算机。

处理流程:shell先读取命令,如果是内置命令就直接执行。如果不是的话就创建子进程,加载命令程序运行,并根据用户的需求在前台或后台运行。在前台时,控制权由程序控制;若在后台运行,则shell仍能继续输入与执行命令。最终当子程序终止后,shell会回收分配给子进程的空间等资源。

6.3 Hello的fork进程创建过程

父进程通过调用fork函数创建一个新的运行的子进程,新创建的子进程几乎但不完全与父进程相同。子进程得到与父进程用户级虚拟地址空间相同(但是独立的)一份副本,包括代码和数据段、堆、共享库以及用户栈,子进程还获得与父进程任何打开文件描述符相同的副本。他们之间最大的区别就是他们有不同的PID。

当运行hello程序时,在交互窗口输入./hello后,此时程序的父进程是shell,它会对这条命令进行解析,并调用fork函数创建一个新的子进程以便接下来将hello加载到这个进程中执行。

6.4 Hello的execve过程

在这个子进程创建出来后,子进程会去调用execve()来加载可执行文件到当前进程,这样,子进程原来的用户区域将会被删除,然后通过虚拟内存机制将可执行文件hello中的各个段映射到对应的代码段、数据段等地址空间,这样就加载了hello的新的用户区域。然后,execve会加载hello用到的共享库(比如上面提到过的ld-2.31.so),也是通过虚拟内存映射的方式。最后,子进程的程序将直接跳转到hello的入口点,进行hello的执行。

6.5 Hello的进程执行

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

由于系统一般会运行多个进程,所以处理器的物理控制流就会被分成多个逻辑控制流。由于进程间轮流使用处理器,内核为每个进程会维持一个上下文,上下文信息就是内核重新启动一个被抢占的进程所需要而定状态,由一些对象的值组成,包括寄存器、程序计数器、用户栈等。而进城间的上下文切换模式如图所示。其中,进程执行他的控制流的一部分的每一时间段都叫作“控制流时间片”。

    为使操作系统内核提供一个无懈可击的进程抽象,处理器必须提供一种机制,限制一个应用可以执行的指令以及可以访问的地址空间范围。处理器会通过某个控制寄存器的一个模式位来提供这个功能。当设置了模式位的时候,进程就运行在内核模式中,它就可以执行指令集中的任何指令,并且可以访问系统中的任何内存位置。没有设置模式位时,进程就运行在用户模式。

当执行hello进程时,系统进行调度,为其分配时间片,当hello下的进程从磁盘内存中读取数据的时候,就会出发陷阱异常,切换到内核模式。此时系统就会重新开始一个先前被抢占了的进程,进行上下文切换。当切换回的进程运行了一段时间后,系统就会将hello由内核态切换为用户态,进行抢占执行,继续执行下一条指令。

6.6 hello的异常与信号处理

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

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

  1. 运行时乱按键盘:

在hello正在运行/休眠的过程中,我在中间不断乱按,发现字符可以正常地被打印在屏幕上,但没有任何作用。这里应该是按下普通按键,产生键盘中断(异步异常),然后切换到内核态,这样内核就知道了按下了某个字符。同时,在hello进程(shell的前台作业)sleep时,shell应该有一个通过内核进行屏幕输入的机制,这时内核就可以把对应字符输出到屏幕上了。

2.Ctrl+c

在hello正在运行/休眠的过程中,我按下了Ctrl+C,然后hello程序直接终止,shell返回到接受命令行的状态。在按下按键时,产生键盘中断(异步异常),转入内核,内核发现是Ctrl+C,它分析Ctrl+C的接收方应当是shell,然后内核对shell发送SIGINT信号,shell在用户态接受到SIGINT信号时执行它的信号处理程序,然后把信号转发到当前运行的前台作业./hello…对应的进程,hello进程收到SIGINT信号后,它没有对应的信号处理程序,直接进行SIGINT的默认操作即结束hello的运行。

3.Ctrl+z

首先我在hello运行过程中按下Ctrl+Z,这和刚才的Ctrl+C机制类似,唯一不同的就是它会使得hello进程接收到信号SIGTSTP,然后hello进程暂停,shell发现它的前台作业暂停了,就重新进入接受用户命令行的状态。然后我输入命令jobs,终端打印出当前的所有作业,发现了暂停的作业./hello…。然后我用命令fg使得暂停的作业hello继续作为前台作业运行,此时进程hello收到信号SIGCONT,继续运行。然后我重新用Ctrl+Z暂停它,用命令ps和pstree打印出所有进程的状态,然后用命令kill终止处于暂停中的hello作业,对其发送一个SIGINT信号,用jobs命令显示其确实已终止。

6.7本章小结

       本章中我们搞清楚了hello的一个进程在运行过程中的各种机制,但是这也只是一个简单的表象,背后仍有各种复杂的机制在支持着这一整个过程的运行,我们需要明白hello绝不是在独立地占用整个cpu运行,而是通过操作系统的各种机制实现的并发进行。同时还对信号进行了深入理解,还体验了异常与信号在程序运行中的过程和机制。

(第61分)

第7章 hello的存储管理

7.1 hello的存储器地址空间

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

逻辑地址是程序直接使用的地址,它表示为“段:偏移地址”的形式,由一个段选择子(一般存在段寄存器中)再加上段内的偏移地址构成。

线性地址(或者叫虚拟地址)是虚拟内存空间内的地址,它对应着虚拟内存空间内的代码或数据,表示为一个64位整数。

虚拟地址是由操作系统分配给应用程序使用的地址,使得应用程序不需要知道物理地址的实际位置就可以调用。对于hello来说,main函数中的段内偏移量就是虚拟地址。

物理地址是真正的内存地址,CPU可以直接将物理地址传送到与内存相连的地址信号线上,对实际存在内存中的数据进行访问。物理地址决定了数据在内存中真正存储在何处。

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

对于一个以“段:偏移地址”形式给出的逻辑地址,CPU将会通过其中的16位段选择子定位到GDT/LDT中的段描述符,通过这个段描述符得到段的基址,与段内偏移地址相加得到的64位整数就是线性地址。这就是CPU的段式管理机制,其中,段的划分,也就是GDT和LDT都是由操作系统内核控制的。

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

虚拟内存机制使用页表的数据结构进行页式管理,它把线性地址空间和物理地址空间划分成大小相同的页,然后通过建立线性地址空间的页同物理地址空间中的页的映射,实现线性地址到物理地址的转化。其对应过程如图所示,MMU利用虚拟页号(VPN)找到对应的物理页号(PPN),然后将找到的PPN与由虚拟页偏移量(VPO)得到物理页偏移量(PPO)组合就构成了实际的物理地址。

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

TLB转换检测缓冲区是一个内存管理单元,其结构如图所示。

其功能是用于改进虚拟地址到物理地址转换速度的缓存,其中每一行都保存着一个由单个PTE(Page Table Entry)组成的块。在使用TLB时,首先会查找相应的组索引中是否有相应的条目,若没有则会按照一定策略进行条目替换。而多级页表解决了页表条目过多的问题,在四级页表的规格下,虚拟地址被分为了4个VPN和1个VPO,根据VPN依次访问各级页表就可以找到对应的PPN,进而实现物理地址的寻址,在Core i7中,VA到PA的变化过程如图所示。

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

Cache是一种在CPU寄存器和物理内存之间的高速存储设备,在三级Cache中分为L1,L2,L3,它们的容量依次增大。

在现在流行的CPU中,Cache的物理地址一般由三部分组成,分别是缓存标记(CT),缓存组索引(CI)以及缓存偏移(CO)。当CPU进行访问时,会依次访问L1,L2,L3,直到命中。如果三级均没命中,则会访问主存。由于在现有的计算机中,3级Cache的结构基本可以涵盖5%的内存,因而能够极大的提升CPU的运行效率。在Core i7中的三级Cache结构如图所示。   

7.6 hello进程fork时的内存映射

当shell使用fork创建子进程时,内核为新的子进程创建各种数据结构,并分配给子进程一个唯一的PID,为了给它创建虚拟内存空间,内核创建了当前进程的mm_struct、区域结构和页表的原样副本,将两个进程的页面都标记为只读,并将两个进程中的每个区域结构都标记为私有的写时复制。这样,在新进程里,最开始的时候它的虚拟内存和原进程的虚拟内存映射相同,但当这两个进程中的任意一个进行写操作时,写时复制机制就会创建新页面,这样两个进程的地址空间就在逻辑上私有了。

7.7 hello进程execve时的内存映射

新进程执行execve加载可执行文件hello,先将当前进程虚拟内存空间中的用户部分的已存在的区域结构删除,再为新程序hello的代码、数据、bss段和栈段区域创建新的区域结构,这些新的区域都是私有且写时复制的。代码和数据区域被映射为hello可执行文件中的.text和.data节,bss区域请求二进制0故映射到匿名文件,栈和堆被初始化为空。然后execve会将hello链接的动态链接库(共享对象)映射到虚拟地址空间的共享区域内。最终跳转到hello的入口点。下图为课本上的一个典型例子:

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

缺页故障:就是要访问的页不在主存,需要操作系统将其调入主存后再进行访问。在这个时候,被内存映射的文件实际上成了一个分页交换文件[4]。

缺页中断处理:如果出现缺页故障,那么此时控制权会交给相应的异常处理程序,该程序会根据一定策略淘汰物理内存中的某个页,然后再从硬盘中调出所需新的所需的页,并更新PTE,并返回到原来的进程,再次执行当前指令。

7.9动态存储分配管理

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

在hello程序中使用的printf,而printf会使用由动态内存分配器动态内存分配机制。动态内存分配器维护进程虚拟地址空间中的的堆区域,它将堆视作一组不同大小的块的集合来维护,每个块是一段连续的虚拟内存碎片,要么是已分配的,要么是空闲的。空闲块保持空闲直至被应用程序分配,以已分配块保持已分配状态直至被释放。

分配器需要一些数据结构维护堆块来区分块边界以及区分已分配块和空闲块,这些可以被标识在块的头部,那么分配器可以将堆组织为一个连续的已分配块和未分配块的序列(称为隐式空闲链表),如下图所示:

这样的话,通过隐式空闲链表,分配器可以通过对于链表的操作以完成在堆上放置已分配的块、分割空闲块、获取额外内存、合并空闲块等操作。于是应用程序就可以动态地在堆上分配额外内存空间了。

7.10本章小结

本章主要介绍了hello的存储管理,先介绍了如何由指令的虚拟地址从逻辑地址通过段式管理转化到线性地址,然后介绍了hello的页式管理,以及VA到PA的变换,再然后介绍了hello进程调用fork和execve进程时的内存映射情况,最后介绍了缺页故障异常处以及动态存储分配管理。

(第7 2分)

第8章 hello的IO管理

8.1 Linux的IO设备管理方法

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

设备的模型化:文件

设备管理:unix io接口

8.2 简述Unix IO接口及其函数

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

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本章小结

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

(第81分)

结论

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

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

hello的一生十分精彩,从Program到Process,从Zero-0到Zero-0,只缘程序员的想要执行。

在预处理阶段,预处理器修改原始的C程序,得到了hello.i文件。

在编译阶段,编译器将文本文件hello.i翻译成文本文件hello.s。

在汇编阶段,汇编器将hello.s翻译成机器语言指令,并将这些指令打包成可重定位目标文件的格式,hello.o就此诞生。

在链接阶段,链接器将hello.o所需的外部库与hello.o合并,得到了hello文件,一个可执行文件就此诞生。

当在shell中输入./hello命令时,fork函数为其创建了子进程,又调用了execave函数将其加载到内存之中,让它能够按照系统安排的控制流时间片执行自己的进程,让它能够感受着I/O设备的信号,响应着系统的信号,调用着相关的函数。

最终,它执行结束,变成了僵死的进程。waitpid函数的Shell父进程会帮助它履行最后的职责——将进程回收,释放空间。

至此,它完成了他自己平淡无奇却又波澜壮阔的一生。

通过对hello的一生的探索,我更加详细的领略了程序的诞生于执行的过程,加深了自己对计算机系统知识的理解,有了更加全面的认识,更领悟了计算机之美。同时,也对前人——那些计算机系统领域的开拓者与建设者充满了无以复加的崇高敬佩。他们从无到有,从小到大,又点滴聚成江海,最终实现了如此复杂的计算机架构。这更激励着我要不断的努力学习,学习更多的计算机知识,为以后在计算机领域的更深入的学习打好基础。

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

附件

列出你为编写本论文,生成的中间结果文件的名字,文件的作用等。

Hello.c 源程序

Hello.i 预处理后的文件

Hello.s 编译后的文件

Hello.o 可重定位目标文件

Hello 可执行目标文件

Helloo.elf hello.o的ELF格式,分析as和链接器的行为

Hello.txt hello.o的反汇编代码

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

参考文献

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

[1] Randal E,Brynant, David R. O’Hallaron. 深入理解计算机系统(原书第三版). 北京:机械工业出版社,2016.

[2] Stallings.计算机组成与体系结构:性能设计(原书第8版). 北京:机械工业出版社,2011.(参考文献0分,缺失 -1分)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值