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

计算机系统

大作业

题     目  程序人生-Hellos P2P  

专       业  未来技术              

班   级    22WL022              

学       生    栀哩                  

指 导 教 师     刘宏伟                

计算机科学与技术学院

20245

摘  要

本文介绍了hello的一生,分别从概述,预处理,编译,汇编,链接,进程管理,存储管理七个方面入手(IO未学习),展示了程序生命的诞生与结束,以达到深入理解计算机系统的目的。

关键词:计算机系统;生命历程;linux;进程;汇编                            

(摘要0分,缺失-1分,根据内容精彩称都酌情加分0-1分

目  录

第1章 概述

1.1 Hello简介

1.2 环境与工具

1.3 中间结果

1.4 本章小结

第2章 预处理

2.1 预处理的概念与作用

2.2在Ubuntu下预处理的命令

2.3 Hello的预处理结果解析

2.4 本章小结

第3章 编译

3.1 编译的概念与作用

3.2 在Ubuntu下编译的命令

3.3 Hello的编译结果解析

3.4 本章小结

第4章 汇编

4.1 汇编的概念与作用

4.2 在Ubuntu下汇编的命令

4.3 可重定位目标elf格式

4.4 Hello.o的结果解析

4.5 本章小结

第5章 链接

5.1 链接的概念与作用

5.2 在Ubuntu下链接的命令

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

5.4 hello的虚拟地址空间

5.5 链接的重定位过程分析

5.6 hello的执行流程

5.7 Hello的动态链接分析

5.8 本章小结

第6章 hello进程管理

6.1 进程的概念与作用

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

6.3 Hello的fork进程创建过程

6.4 Hello的execve过程

6.5 Hello的进程执行

6.6 hello的异常与信号处理

6.7本章小结

第7章 hello的存储管理

7.1 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动态存储分配管理

7.10本章小结

第8章 hello的IO管理

8.1 Linux的IO设备管理方法

8.2 简述Unix IO接口及其函数

8.3 printf的实现分析

8.4 getchar的实现分析

8.5本章小结

结论

附件

参考文献


第1章 概述

1.1 Hello简介

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

P2PFrom Program to Process,从hello.c这一个程序开始,经过预处理、编译、汇编、链接生成可执行目标,在shell中,输入运行指令后,shell解析参数,为其fork一个子进程,内核为其创建数据结构,此时hello就从程序变为进程(Process)

020From Zero-0 to Zero-0shell为其调用execve,映射虚拟内存,进入程序入口后载入物理内存,然后进入 main函数执行目标代码,CPU为运行的hello分配时间片,执行逻辑控制流,将内容输出。当程序运行结束后,父进程回收hello进程,内核删除相关数据结构,回收其内存空间。

1.2 环境与工具

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

硬件环境:12th Gen Intel(R) Core(TM) i7-12700H   2.30 GHz

软件环境:Windows 11;Vmware 16;Ubuntu 16.04

开发与调试工具:CodeBlocks;visual studio2022;gcc、edb

1.3 中间结果

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

hello.ihello.c预处理生成的文本文件,分析预处理器行为

hello.s:由hello.i经编译器编译后产生的汇编文件,分析编译器行为

hello.o:由hello.s经汇编器处理后产生的可重定位目标文件,分析汇编器行为

hello.out:链接之后生成的可执行目标文件 ,分析链接器行为

1.4 本章小结

hello.c程序从编写、预处理、编译、汇编、链接再到执行,体现了计算机系统系统各部分的具体功能,以及它们之间的的协同合作。

(第1章0.5分)


第2章 预处理

2.1 预处理的概念与作用

概念:预处理器在程序编译之前,根据以字符#开头的命令(头文件、define等),修改原始的C程序,将引用的所有库展开合并成为一个完整的文本文件。

作用:

1.#include形式将源文件中声明的文件复制到新的程序中。

2.#define将数值或字符定义为字符串

3.方便编译器在对程序进行翻译的时候更加方便。

2.2在Ubuntu下预处理的命令

图1:指令

图2:结果

2.3 Hello的预处理结果解析

图3:hello.i文件源程序

图4:hello.c内容

经过预处理后,原本不到三十行的程序生成了三千多行的代码。多为一些外部程序的引用和部分声明。

2.4 本章小结

本章节简单介绍了c语言在编译前的预处理过程,简单介绍了预处理过程的概念和作用,在Ubuntu下预处理的命令以及处理的结果预处理可以添加需要的条件编译和完善程序文本文件等。从预处理指令到预处理后的文件的改变,我们可以看到程序的生成其实是很困难的,远不是我们表面看上去的那么简单。

(第2章0.5分)


第3章 编译

3.1 编译的概念与作用

编译是把用高级程序设计语言书写的源程序,翻译成等价的机器语言格式目标程序的翻译程序。编译程序属于采用生成性实现途径实现的翻译程序。其以高级程序设计语言书写的源程序作为输入,而以汇编语言或机器语言表示的目标程序作为输出。

编译的作用包括:词法分析、语义分析、源代码优化、代码生成、目标代码优化。

3.2 在Ubuntu下编译的命令

图5:编译命令

图6:生成hello.s文件

3.3 Hello的编译结果解析

3.31文件信息

图7:文件信息部分截图

.file表明了源文件,.text代码段,.section .radata只读代码段,.align对齐方式为8字节对齐,.string字符串,.global全局变量,.type声明main是函数类型。

3.32数据传输

mov指令控制数据的传输,将原位置传输到目的位置,原位置不变。包括寄存器间的传输,立即数向寄存器传输。movq和movl的区别在于传输数据的位数大小。

                      

                       

                       

                       图8:部分mov指令截图

3.33程序调用

call指令可以实现调用一个子程序,在子程序里使用ret指令结束子程序的执行并返回主程序,主程序继续往下执行。  

                

                   图9:程序调用指令截图

3.34栈操作

对栈的操作包括压入、弹出栈,开辟栈空间。

                       

图10:压入栈

图11:开辟空间

3.35条件控制

cmp操作是根据后者减前者的值来设置条件码寄存器,然后通过条件码的组合或者是运算来得到是否跳转的命令。

                

                   图12:条件控制指令截图

3.36跳转指令               

                    

                      

                     

                   图13:跳转指令部分截图

jle为有符号小于等于则跳转;jmp为无条件跳转;je为相等则跳转。

3.37函数返回

                    

                    图14:函数返回部分截图

函数返回经过恢复调用者寄存器值,弹出旧的栈帧%rbp,返回原函数下一条指令地址,以ret指令结束。

3.4 本章小结

本章核心在于对于汇编代码的理解,主要包括以下方面:1.文件信息 2.数据传输 3.程序调用 4.栈操作 5.条件控制 6.跳转指令 7.函数返回。

我们可以根据汇编代码编写出对应C语言代码,并且了解到各参数在程序运行中的传输过程。

(第3章2分)


第4章 汇编

4.1 汇编的概念与作用

汇编是指汇编器将汇编程序翻译为机器语言指令,然后把这些指令打包成可重定位目标程序的格式,并将结果保存在目标文件中

作用:将汇编语言翻译为可重定位的二进制.o文件。

4.2 在Ubuntu下汇编的命令  

图15:汇编命令

          

                     图16:生成二进制.o文件

4.3 可重定位目标elf格式

    

图17:ELF头

ELF 头:用于总的描述ELF文件各个信息的段。hello.o是可重定位文件,采用补码、小端序。内容包括ELF header的大小,每个条目的大小和条目数量。

             

图18:节头表

节头表包括:

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

.rodata:只读数据,比如printf语句中的格式串和开关语句中的跳转表

.data:已初始化的全局和静态C变量。局部局部C变量在运行的时候保存在栈中,既不出现在.data节中,也不出现在.bss节中。

.bss:未初始化的全局和静态C变量,以及所有被初始化为0的全局或静态C变量。在目标文件中这个节不占用实际的空间,它仅仅是一个占位符。目标文件格式区分已初始化和未初始化变量是为了空间效率:在目标文件中,未初始化变量不需要占据任何实际的磁盘空间。运行时,在内存中分配这些变量,初始值为0。

.symtab:一个符号表,它存放在程序中定义和引用的的函数和全局变量的信息。一些程序员错误地认为必须通过-g选项来编译一个程序,才能得到符号表信息。实际上,每个可重定位目标文件在.symtab中都有一张符号表。然而,和编译器中的符号表不同,.symtab符号表不包含局部变量的条目。

.rel.text:;一个.text节中位置的列表,当链接器把这个目标文件和其他文件组合时,需要修改这些位置。

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

.debug:一个调试符号表,其条目时程序中定义的局部变量和类型定义,程序中定义和引用的全局变量,以及原始的C源文件。

.line:原始C程序中的行号和.text节中机器指令之间的映射。

.strtab:一个字符串表,其内容包括.symtab和.debug节中的符号表,以及节头部中的节名字。

图19:重定位节

重定位节:包含了.text(具体指令)节中需要进行重定位的信息。这些信息描述的位置,在由.o文件生成可执行文件的时候需要被修改(重定位)。

4.4 Hello.o的结果解析

图20:hello.o反汇编结果

对比:

1.反汇编代码中有位置信息,而hello.s中没有

2.hello.s中call后跟的是函数名,而hello.o的反汇编中,call后跟的是下一条指令

3.hello.s中直接跳转的跳转目标是用.L2,.L3,.L4等标号表示的,而hello.o的反汇编中跳转目标用main+偏移量来表示

4.汇编语言的操作数是十进制,机器语言的操作数是十六进制

4.5 本章小结

本章我们把汇编语言源程序汇编成了可重定位的目标文件。分析了可重定位的目标文件的elf格式,elf头、节头表同时对hello.o文件进行反汇编,并与hello.s文件内容进行对比。

(第4章1分)


5链接

5.1 链接的概念与作用

概念:在链接过程中,把相关的代码和数据连接到一个可执行文件中,这个文件可加载。链接行为可以在编译/汇编/加载/运行时执行。

作用:链接器在软件开发中扮演着一个关键的角色,因为他们使得分离编译成为可能。我们不用将一个大型的应用程序组织为一个巨大的源文件,而是可以把它分解为更小、更好管理的模块,可以独立地修改和编译这些模块。当我们改变这些模块中的一个时,只需要简单地重新编译它,并重新链接应用,而不是重新编译其他文件

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

图21:链接命令

                      图22:链接生成可执行文件

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

          

图23:可执行目标文件ELF头截图

观察到可执行目标文件和可重定位文件的ELF头非常类似,二者类型上不同。

图24:hello可执行文件的ELF其余内容

可发现可执行文件和可冲顶文件的ELF中都包含ELF头、节头表、程序头表、.text 节、.rodata节、.bss节、.symtab节、.debug节。增加了.init节。

5.4 hello的虚拟地址空间

     

                 图26:edb下观察虚拟地址空间

可以观察到.ELF的起始地址为0x400000

虚拟地址起始空间为401000。这与ELF头表中的.init节的地址相对应。

                 图27:hello可执行文件ELF头表信息

5.5 链接的重定位过程分析

图28:hello的反汇编代码

可以看出,hello的反汇编代码和hello.o的相比,多出来许多。hello反汇编代码中多了很多节。例如.init节就是程序初始化需要执行的代码所在的节,动态链接信息的节等等。hello中跳转指令后接的为虚拟地址,而hello.o后接绝对地址。

5.6 hello的执行流程

子程序名:地址

<_init>:401000

<.plt>:401020

<puts@plt> :401090

<printf@plt>:4010a0

<getchar@plt>:4010b0

<atoi@plt>:4010c0

<exit@plt>:4010d0

<sleep@plt>:4010e0

<_start>:4010f0

<_dl_relocate_static_pie>:401120

<main> :401125

<_libc_scu_init>:4011c0

<_libc_csu_fini>:401230

<_fini>: 401238

5.7 Hello的动态链接分析

                     图29:.got和.plt的位置

图30:链接前

图31:链接后

5.8 本章小结

本章中介绍了链接的概念与作用。观察了hello文件ELF格式下的内容。利用edb观察了hello的虚拟地址空间使用情况并以hello为例对重定位过程、执行过程和动态链接过程进行分析。

(第5章1分)


6hello进程管理

6.1 进程的概念与作用

概念:一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,一个进程可以有多个线程包括文本区域、数据区域和堆栈。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量

作用:进程提供给应用程序两个关键的抽象。一个独立的逻辑控制流,他提供一个假象,好像我们的程序独占的使用处理器。一个私有的地址空间,它提供一个假象,好像我们的程序独占的使用内存系统。每次用户通过向shell 输入一个可执行目标文件的名字,运行程序时, shell 就会创建一个新的进程,然后在这个新进程的上下文中运行这个可执行目标文件。应用程序也能够创建新进程,并且在这个新进程的上下文中运行它们自己的代码或其他应用程序。

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

作用:Shell 应用程序提供了一个界面,用户通过这个界面访问操作系统内
核的服务。
处理流程:
1)从终端读入输入的命令。
2)将输入字符串切分获得所有的参数
3)如果是内置命令则立即执行
4否则调用相应的程序执行
5)shell 应该接受键盘输入信号,并对这些信号进行相应处理。

6.3 Hello的fork进程创建过程

(1)给新进程分配一个标识符

(2)在内核中分配一个PCB,将其挂在PCB表上

(3)复制它的父进程的环境(PCB中大部分的内容)

(4)为其分配资源(程序、数据、栈等)

(5)复制父进程地址空间里的内容(代码共享,数据写时拷贝)

(6)将进程置成就绪状态,并将其放入就绪队列,等待CPU调度。

关于fork()函数:

调用一次,返回二次。一旦调用fork()函数,会生成一份与源文件一模一样的程序,这就是子进程,当然了,如果子进程创建成功,父进程的fork()函数返回子进程的pid号码(大于0),这时,子进程的fork()函数返回0;但是如果子进程创建失败,父进程的fork()函数返回-1,这时子进程都没有创建,当然也就没有返回了。

6.4 Hello的execve过程

三个参数:可执行目标文件名finename、参数列表argv、环境变量列表envp。

execve() 系统调用的作用是运行另外一个指定的程序。它会把新程序加载到当前进程的内存空间内,当前的进程会被丢弃,它的堆、栈和所有的段数据都会被新进程相应的部分代替,然后会从新程序的初始化代码和main函数开始运行。同时,进程的ID将保持不变。

6.5 Hello的进程执行

(1)逻辑控制流

逻辑控制流是一个PC值的序列,PC值指程序计数器的值,这些值与可执行目标文件的指令或者包含在运行时动态链接到程序的共享对象中的指令一一对应。

(2)上下文

上下文就是内核重新启动一个被抢占的进程所需要的状态。它由一些对象的值组成,这些对象包括通用目的寄存器、浮点寄存器、程序计数器、用户栈、状态寄存器、内核栈和各种内核数据结构,比如描述地址空间的页表、包含有关当前进程信息的进程表,以及包含进程已打开文件的信息的文件表。

(3)进程调度

进程调度:在进程执行的某些时刻,内核可以决定抢占当前进程,并重新开始一个先前被抢占了的进程的决定

6.6 hello的异常与信号处理

hello出现的异常:中断,陷阱(即系统调用)

hello产生的信号:SIGINT、SIGTSTP、SIGCONT、SIGCHLD

中断:中断是来自处理器外部的I/O设备的信号的结果。

陷阱:陷阱是有意的异常,是执行一条指令的结果。就像中断处理程序一样,陷阱处理程序将控制返回到下一条指令。陷阱最重要的用途是在用户程序和内核之间提供一个像过程一样的接口,叫做系统调用。

图29:进程收到信号终止

我们首先先执行hello程序,执行过程中输入任意字母,仍然正常执行在执行了一会后输入Ctrl+C,直接终止它。进程会收到一个SIGINT信号。

图30:pstree观察进程树

图31:进程的中断

进程运行时输入ctrl+z使得进程中断。

图32:fg调用程序至前台

图33:杀死进程

6.7本章小结

通过对进程的学习和了解,我们熟悉了shell,fork,execve的相关概念,对异常和信号有了初步的认识,懂得了计算机通过并发执行激发性能,知道系统如何稳定运行并且始终保持高效。

(第6章1分)


7hello的存储管理

7.1 hello的存储器地址空间

1.逻辑地址

       程序经过编译后出现在汇编代码中的地址,逻辑地址用来指定一个操作数或者是一条指令的地址。是由一个段标识符加上一个指定段内相对地址的偏移量,表示为段标识符:段内偏移量。

2.线性地址

       逻辑地址到物理地址之间变换的中间层,在分段不见中逻辑地址就是段总的偏移地址,加上段的及地址就可以得到线性地址。

3.虚拟地址

       CPU启动保护模式之后,程序运行在虚拟地址空间中,虚拟地址空间是所有可能地址的集合,对于一个32位的机器而言,则集合中共有2^32种可能。

4.物理地址

       在存储器中以字节为单位存储信息,每一个字节单元与一个唯一的存储器地址一一对应,称为物理地址,又叫实际地址或者是绝对地址。物理地址对应了系统中实际的内存字节。

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

在段式存储管理中,将程序的地址空间划分为若干个段,这样每个进程有一个二维的地址空间。在前面所介绍的动态分区分配方式中,系统为整个进程分配一个连续的内存空间。而在段式存储管理系统中,则为每个段分配一个连续的分区,而进程中的各个段可以不连续地存放在内存的不同分区中。

程序加载时,操作系统为所有段分配其所需内存,这些段不必连续,物理内存的管理采用动态分区的管理方法。在为某个段分配物理内存时,可以采用首先适配法、下次适配法、最佳适配法等方法。在回收某个段所占用的空间时,要注意将收回的空间与其相邻的空间合并。段式存储管理也需要硬件支持,实现逻辑地址到物理地址的映射。

程序通过分段划分为多个模块,如代码段、数据段、共享段:可以分别编写和编译;可以针对不同类型的段采取不同的保护;可以按段为单位来进行共享,包括通过动态链接进行代码共享。这样做的优点是:可以分别编写和编译源程序的一个文件,并且可以针对不同类型的段采取不同的保护,也可以按段为单位来进行共享。

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

将程序的逻辑地址空间划分为固定大小的页,而物理内存划分为同样大小的页框。程序加载时,可将任意一页放人内存中任意一个页框,这些页框不必连续,从而实现了离散分配。该方法需要CPU的硬件支持,来实现逻辑地址和物理地址之间的映射。

在页式系统中进程建立时,操作系统为进程中所有的页分配页框。当进程撤销时收回所有分配给它的页框。在程序的运行期间,如果允许进程动态地申请空间,操作系统还要为进程申请的空间分配物理页框。操作系统为了完成这些功能,必须记录系统内存中实际的页框使用情况。操作系统还要在进程切换时,正确地切换两个不同的进程地址空间到物理内存空间的映射。这就要求操作系统要记录每个进程页表的相关信息。

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

线性地址到物理地址之间的转换通过使用分页机制完成。分页机制是指将虚拟内存分割为虚拟页的大小固定的块。

为判断虚拟页是否缓存在DRAM的某个地方,并确定虚拟页所在的物理页位置,因此需要一个页表。页表是一个页表条目(PTE)的数组,每个PTE由一个有效位和一个n位地址字段组成,有效位的设置与否表明了虚拟页是否被DRAM缓存。在地址翻译过程中,需要用到一个页表基址寄存器,指向当前页表。一个n位虚拟地址包含两个部分,一是p位的虚拟页面偏移,二是一个n-p位的虚拟页号。在虚拟页已被缓存的情况下,页面命中,MMU利用VPN来选择合适的PTE,将页表条目中的物理页号和虚拟地址中的虚拟页面偏移结合起来就可以得到一个物理地址。而如果虚拟页没有被缓存,那么就需要处理缺页,触发缺页异常,并将控制传递到缺页异常处理程序,缺页处理程序能够确定物理内存中的牺牲页,进而判断是否因被修改过而需要调出内存,完成牺牲页的替换之后,则调入新的页面,并更新内存中的PTE,最后返回到原来进程,将引起缺页的虚拟地址重新发给MMU,这次便变成了命中的情况。

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

得到物理地址之后,先将物理地址拆分成CT(标记)+CI(索引)+CO(偏移量),然后L1cache内部找,了L1里面以后,寻找物理地址检测是否命中,如果未能寻找到标记位为有效的字节(miss)的话就去二级和三级cache中寻找对应的字节,找到之后返回结果。到这里就是使用到我们的CPU的高速缓存机制了,使得机器在翻译地址的时候的性能得以充分发挥。

7.6 hello进程fork时的内存映射

在shell中输入命令./hello后,内核调用fork函数创建子进程,为hello程序的运行创建上下文,并分配一个与父进程不同的唯一的PID。为了给子进程创建虚拟内存,创建了当前进程的 mm_struct、区域结构和页表的原样副本。将这两个进程的每个页面都标记为只读,并将两个进程中的每个区域结构都标记为私有的写时复制。

7.7 hello进程execve时的内存映射

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

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

缺页故障:虚拟内存在DRAM缓存不命中即为缺页故障。

缺页中断处理:发生缺页故障时启动缺页处理程序

1、缺页处理程序确认出物理内存中的牺牲页,如果这个页已经被修改了,则把它换到磁盘。

2、缺页处理程序页面调入新的页面,并更新内存中的PTE

3、缺页处理程序返回到原来的进程,再次执行导致缺页的命令。

7.9动态存储分配管理

动态内存分配器维护着一个进程的虚拟内存区域,称为堆。系统之间细节不同,但是不失通用性,假设堆是一个请求二进制零的区域,它紧接在未初始化的数据区域后开始,并向上生长(向更高地址)。对于每个进程,内核维护着一个变量brk(读作“break”),它指向堆的顶部。

分配器风格:显式分配器和隐式分配器。

7.10本章小结

本章简要介绍了hello的存储地址空间。简单讲述了逻辑地址、虚拟地址、物理地址与线性地址的概念与转换方法,介绍了进程fork和execve时的内存映射的内容,描述了系统如何应对那些缺页异常,介绍了动态内存分配管理的方法

(第7章 2分)


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

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

(第8章1分)

结论

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

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

历程:

(1)编写hello.c的源程序

(2)预处理,将c文件调用的库与原本的c文件进行合并,得到hello.i文本文件

(3)编译:hello.i编译生成汇编语言文件hello.s

(4)汇编:hello.s汇编得到二进制可重定位目标文件hello.o

(5)链接:hello.o与其它调用库函数所在的可重定位目标文件和动态链接库链接生可执行文件hello,hello至此可以被加载入内存并运行。

(6)创建进程:终端shell调用fork函数,创建一个子进程,为程序的加载运行提供虚拟内存空间等上下文

(7)加载程序:shell调用execve函数,启动加载器映射虚拟内存,之后开始载入物理内存,在进入main函数

(8)访问内存:通过TLB和多级页表,实现虚拟内存和物理内存的翻译,进而访问计算机的存储结构,访问内存。

(9)IO:hello输入输出与外界进行交互,与Linux IO的抽象有关

(10)终止:hello被父进程回收,内核收回为其创建的所有信息。

非常遗憾这学期没有能够学习完CSAPP的全部内容,在众多课程的压力下,学习效率甚低,辜负了老师和助教的热情和付出,但总的来说,非常感谢一学期老师的陪伴与帮助,受益匪浅!

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


附件

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

hello 可执行文件

hello.elf  hello可执行文件的ELF格式

hello.o.elf  hello.o的 ELF 格式

hello.o 汇编之后的可重定位目标文件

hello.s 编译之后的汇编文件

hello.i 预处理后的文件

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

计算机系统

大作业

题     目  程序人生-Hellos P2P  

专       业  未来技术               

学     号   2022111473             

班   级    22WL022             

学       生    任至立                

指 导 教 师     刘宏伟                

计算机科学与技术学院

20245

摘  要

本文介绍了hello的一生,分别从概述,预处理,编译,汇编,链接,进程管理,存储管理七个方面入手(IO未学习),展示了程序生命的诞生与结束,以达到深入理解计算机系统的目的。

关键词:计算机系统;生命历程;linux;进程;汇编                            

(摘要0分,缺失-1分,根据内容精彩称都酌情加分0-1分

目  录

第1章 概述

1.1 Hello简介

1.2 环境与工具

1.3 中间结果

1.4 本章小结

第2章 预处理

2.1 预处理的概念与作用

2.2在Ubuntu下预处理的命令

2.3 Hello的预处理结果解析

2.4 本章小结

第3章 编译

3.1 编译的概念与作用

3.2 在Ubuntu下编译的命令

3.3 Hello的编译结果解析

3.4 本章小结

第4章 汇编

4.1 汇编的概念与作用

4.2 在Ubuntu下汇编的命令

4.3 可重定位目标elf格式

4.4 Hello.o的结果解析

4.5 本章小结

第5章 链接

5.1 链接的概念与作用

5.2 在Ubuntu下链接的命令

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

5.4 hello的虚拟地址空间

5.5 链接的重定位过程分析

5.6 hello的执行流程

5.7 Hello的动态链接分析

5.8 本章小结

第6章 hello进程管理

6.1 进程的概念与作用

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

6.3 Hello的fork进程创建过程

6.4 Hello的execve过程

6.5 Hello的进程执行

6.6 hello的异常与信号处理

6.7本章小结

第7章 hello的存储管理

7.1 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动态存储分配管理

7.10本章小结

第8章 hello的IO管理

8.1 Linux的IO设备管理方法

8.2 简述Unix IO接口及其函数

8.3 printf的实现分析

8.4 getchar的实现分析

8.5本章小结

结论

附件

参考文献


第1章 概述

1.1 Hello简介

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

P2PFrom Program to Process,从hello.c这一个程序开始,经过预处理、编译、汇编、链接生成可执行目标,在shell中,输入运行指令后,shell解析参数,为其fork一个子进程,内核为其创建数据结构,此时hello就从程序变为进程(Process)

020From Zero-0 to Zero-0shell为其调用execve,映射虚拟内存,进入程序入口后载入物理内存,然后进入 main函数执行目标代码,CPU为运行的hello分配时间片,执行逻辑控制流,将内容输出。当程序运行结束后,父进程回收hello进程,内核删除相关数据结构,回收其内存空间。

1.2 环境与工具

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

硬件环境:12th Gen Intel(R) Core(TM) i7-12700H   2.30 GHz

软件环境:Windows 11;Vmware 16;Ubuntu 16.04

开发与调试工具:CodeBlocks;visual studio2022;gcc、edb

1.3 中间结果

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

hello.ihello.c预处理生成的文本文件,分析预处理器行为

hello.s:由hello.i经编译器编译后产生的汇编文件,分析编译器行为

hello.o:由hello.s经汇编器处理后产生的可重定位目标文件,分析汇编器行为

hello.out:链接之后生成的可执行目标文件 ,分析链接器行为

1.4 本章小结

hello.c程序从编写、预处理、编译、汇编、链接再到执行,体现了计算机系统系统各部分的具体功能,以及它们之间的的协同合作。

(第1章0.5分)


第2章 预处理

2.1 预处理的概念与作用

概念:预处理器在程序编译之前,根据以字符#开头的命令(头文件、define等),修改原始的C程序,将引用的所有库展开合并成为一个完整的文本文件。

作用:

1.#include形式将源文件中声明的文件复制到新的程序中。

2.#define将数值或字符定义为字符串

3.方便编译器在对程序进行翻译的时候更加方便。

2.2在Ubuntu下预处理的命令

图1:指令

图2:结果

2.3 Hello的预处理结果解析

图3:hello.i文件源程序

图4:hello.c内容

经过预处理后,原本不到三十行的程序生成了三千多行的代码。多为一些外部程序的引用和部分声明。

2.4 本章小结

本章节简单介绍了c语言在编译前的预处理过程,简单介绍了预处理过程的概念和作用,在Ubuntu下预处理的命令以及处理的结果预处理可以添加需要的条件编译和完善程序文本文件等。从预处理指令到预处理后的文件的改变,我们可以看到程序的生成其实是很困难的,远不是我们表面看上去的那么简单。

(第2章0.5分)


第3章 编译

3.1 编译的概念与作用

编译是把用高级程序设计语言书写的源程序,翻译成等价的机器语言格式目标程序的翻译程序。编译程序属于采用生成性实现途径实现的翻译程序。其以高级程序设计语言书写的源程序作为输入,而以汇编语言或机器语言表示的目标程序作为输出。

编译的作用包括:词法分析、语义分析、源代码优化、代码生成、目标代码优化。

3.2 在Ubuntu下编译的命令

图5:编译命令

图6:生成hello.s文件

3.3 Hello的编译结果解析

3.31文件信息

图7:文件信息部分截图

.file表明了源文件,.text代码段,.section .radata只读代码段,.align对齐方式为8字节对齐,.string字符串,.global全局变量,.type声明main是函数类型。

3.32数据传输

mov指令控制数据的传输,将原位置传输到目的位置,原位置不变。包括寄存器间的传输,立即数向寄存器传输。movq和movl的区别在于传输数据的位数大小。

                      

                       

                       

                       图8:部分mov指令截图

3.33程序调用

call指令可以实现调用一个子程序,在子程序里使用ret指令结束子程序的执行并返回主程序,主程序继续往下执行。  

                

                   图9:程序调用指令截图

3.34栈操作

对栈的操作包括压入、弹出栈,开辟栈空间。

                       

图10:压入栈

图11:开辟空间

3.35条件控制

cmp操作是根据后者减前者的值来设置条件码寄存器,然后通过条件码的组合或者是运算来得到是否跳转的命令。

                

                   图12:条件控制指令截图

3.36跳转指令               

                    

                      

                     

                   图13:跳转指令部分截图

jle为有符号小于等于则跳转;jmp为无条件跳转;je为相等则跳转。

3.37函数返回

                    

                    图14:函数返回部分截图

函数返回经过恢复调用者寄存器值,弹出旧的栈帧%rbp,返回原函数下一条指令地址,以ret指令结束。

3.4 本章小结

本章核心在于对于汇编代码的理解,主要包括以下方面:1.文件信息 2.数据传输 3.程序调用 4.栈操作 5.条件控制 6.跳转指令 7.函数返回。

我们可以根据汇编代码编写出对应C语言代码,并且了解到各参数在程序运行中的传输过程。

(第3章2分)


第4章 汇编

4.1 汇编的概念与作用

汇编是指汇编器将汇编程序翻译为机器语言指令,然后把这些指令打包成可重定位目标程序的格式,并将结果保存在目标文件中

作用:将汇编语言翻译为可重定位的二进制.o文件。

4.2 在Ubuntu下汇编的命令  

图15:汇编命令

          

                     图16:生成二进制.o文件

4.3 可重定位目标elf格式

    

图17:ELF头

ELF 头:用于总的描述ELF文件各个信息的段。hello.o是可重定位文件,采用补码、小端序。内容包括ELF header的大小,每个条目的大小和条目数量。

             

图18:节头表

节头表包括:

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

.rodata:只读数据,比如printf语句中的格式串和开关语句中的跳转表

.data:已初始化的全局和静态C变量。局部局部C变量在运行的时候保存在栈中,既不出现在.data节中,也不出现在.bss节中。

.bss:未初始化的全局和静态C变量,以及所有被初始化为0的全局或静态C变量。在目标文件中这个节不占用实际的空间,它仅仅是一个占位符。目标文件格式区分已初始化和未初始化变量是为了空间效率:在目标文件中,未初始化变量不需要占据任何实际的磁盘空间。运行时,在内存中分配这些变量,初始值为0。

.symtab:一个符号表,它存放在程序中定义和引用的的函数和全局变量的信息。一些程序员错误地认为必须通过-g选项来编译一个程序,才能得到符号表信息。实际上,每个可重定位目标文件在.symtab中都有一张符号表。然而,和编译器中的符号表不同,.symtab符号表不包含局部变量的条目。

.rel.text:;一个.text节中位置的列表,当链接器把这个目标文件和其他文件组合时,需要修改这些位置。

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

.debug:一个调试符号表,其条目时程序中定义的局部变量和类型定义,程序中定义和引用的全局变量,以及原始的C源文件。

.line:原始C程序中的行号和.text节中机器指令之间的映射。

.strtab:一个字符串表,其内容包括.symtab和.debug节中的符号表,以及节头部中的节名字。

图19:重定位节

重定位节:包含了.text(具体指令)节中需要进行重定位的信息。这些信息描述的位置,在由.o文件生成可执行文件的时候需要被修改(重定位)。

4.4 Hello.o的结果解析

图20:hello.o反汇编结果

对比:

1.反汇编代码中有位置信息,而hello.s中没有

2.hello.s中call后跟的是函数名,而hello.o的反汇编中,call后跟的是下一条指令

3.hello.s中直接跳转的跳转目标是用.L2,.L3,.L4等标号表示的,而hello.o的反汇编中跳转目标用main+偏移量来表示

4.汇编语言的操作数是十进制,机器语言的操作数是十六进制

4.5 本章小结

本章我们把汇编语言源程序汇编成了可重定位的目标文件。分析了可重定位的目标文件的elf格式,elf头、节头表同时对hello.o文件进行反汇编,并与hello.s文件内容进行对比。

(第4章1分)


5链接

5.1 链接的概念与作用

概念:在链接过程中,把相关的代码和数据连接到一个可执行文件中,这个文件可加载。链接行为可以在编译/汇编/加载/运行时执行。

作用:链接器在软件开发中扮演着一个关键的角色,因为他们使得分离编译成为可能。我们不用将一个大型的应用程序组织为一个巨大的源文件,而是可以把它分解为更小、更好管理的模块,可以独立地修改和编译这些模块。当我们改变这些模块中的一个时,只需要简单地重新编译它,并重新链接应用,而不是重新编译其他文件

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

图21:链接命令

                      图22:链接生成可执行文件

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

          

图23:可执行目标文件ELF头截图

观察到可执行目标文件和可重定位文件的ELF头非常类似,二者类型上不同。

图24:hello可执行文件的ELF其余内容

可发现可执行文件和可冲顶文件的ELF中都包含ELF头、节头表、程序头表、.text 节、.rodata节、.bss节、.symtab节、.debug节。增加了.init节。

5.4 hello的虚拟地址空间

     

                 图26:edb下观察虚拟地址空间

可以观察到.ELF的起始地址为0x400000

虚拟地址起始空间为401000。这与ELF头表中的.init节的地址相对应。

                 图27:hello可执行文件ELF头表信息

5.5 链接的重定位过程分析

图28:hello的反汇编代码

可以看出,hello的反汇编代码和hello.o的相比,多出来许多。hello反汇编代码中多了很多节。例如.init节就是程序初始化需要执行的代码所在的节,动态链接信息的节等等。hello中跳转指令后接的为虚拟地址,而hello.o后接绝对地址。

5.6 hello的执行流程

子程序名:地址

<_init>:401000

<.plt>:401020

<puts@plt> :401090

<printf@plt>:4010a0

<getchar@plt>:4010b0

<atoi@plt>:4010c0

<exit@plt>:4010d0

<sleep@plt>:4010e0

<_start>:4010f0

<_dl_relocate_static_pie>:401120

<main> :401125

<_libc_scu_init>:4011c0

<_libc_csu_fini>:401230

<_fini>: 401238

5.7 Hello的动态链接分析

                     图29:.got和.plt的位置

图30:链接前

图31:链接后

5.8 本章小结

本章中介绍了链接的概念与作用。观察了hello文件ELF格式下的内容。利用edb观察了hello的虚拟地址空间使用情况并以hello为例对重定位过程、执行过程和动态链接过程进行分析。

(第5章1分)


6hello进程管理

6.1 进程的概念与作用

概念:一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,一个进程可以有多个线程包括文本区域、数据区域和堆栈。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量

作用:进程提供给应用程序两个关键的抽象。一个独立的逻辑控制流,他提供一个假象,好像我们的程序独占的使用处理器。一个私有的地址空间,它提供一个假象,好像我们的程序独占的使用内存系统。每次用户通过向shell 输入一个可执行目标文件的名字,运行程序时, shell 就会创建一个新的进程,然后在这个新进程的上下文中运行这个可执行目标文件。应用程序也能够创建新进程,并且在这个新进程的上下文中运行它们自己的代码或其他应用程序。

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

作用:Shell 应用程序提供了一个界面,用户通过这个界面访问操作系统内
核的服务。
处理流程:
1)从终端读入输入的命令。
2)将输入字符串切分获得所有的参数
3)如果是内置命令则立即执行
4否则调用相应的程序执行
5)shell 应该接受键盘输入信号,并对这些信号进行相应处理。

6.3 Hello的fork进程创建过程

(1)给新进程分配一个标识符

(2)在内核中分配一个PCB,将其挂在PCB表上

(3)复制它的父进程的环境(PCB中大部分的内容)

(4)为其分配资源(程序、数据、栈等)

(5)复制父进程地址空间里的内容(代码共享,数据写时拷贝)

(6)将进程置成就绪状态,并将其放入就绪队列,等待CPU调度。

关于fork()函数:

调用一次,返回二次。一旦调用fork()函数,会生成一份与源文件一模一样的程序,这就是子进程,当然了,如果子进程创建成功,父进程的fork()函数返回子进程的pid号码(大于0),这时,子进程的fork()函数返回0;但是如果子进程创建失败,父进程的fork()函数返回-1,这时子进程都没有创建,当然也就没有返回了。

6.4 Hello的execve过程

三个参数:可执行目标文件名finename、参数列表argv、环境变量列表envp。

execve() 系统调用的作用是运行另外一个指定的程序。它会把新程序加载到当前进程的内存空间内,当前的进程会被丢弃,它的堆、栈和所有的段数据都会被新进程相应的部分代替,然后会从新程序的初始化代码和main函数开始运行。同时,进程的ID将保持不变。

6.5 Hello的进程执行

(1)逻辑控制流

逻辑控制流是一个PC值的序列,PC值指程序计数器的值,这些值与可执行目标文件的指令或者包含在运行时动态链接到程序的共享对象中的指令一一对应。

(2)上下文

上下文就是内核重新启动一个被抢占的进程所需要的状态。它由一些对象的值组成,这些对象包括通用目的寄存器、浮点寄存器、程序计数器、用户栈、状态寄存器、内核栈和各种内核数据结构,比如描述地址空间的页表、包含有关当前进程信息的进程表,以及包含进程已打开文件的信息的文件表。

(3)进程调度

进程调度:在进程执行的某些时刻,内核可以决定抢占当前进程,并重新开始一个先前被抢占了的进程的决定

6.6 hello的异常与信号处理

hello出现的异常:中断,陷阱(即系统调用)

hello产生的信号:SIGINT、SIGTSTP、SIGCONT、SIGCHLD

中断:中断是来自处理器外部的I/O设备的信号的结果。

陷阱:陷阱是有意的异常,是执行一条指令的结果。就像中断处理程序一样,陷阱处理程序将控制返回到下一条指令。陷阱最重要的用途是在用户程序和内核之间提供一个像过程一样的接口,叫做系统调用。

图29:进程收到信号终止

我们首先先执行hello程序,执行过程中输入任意字母,仍然正常执行在执行了一会后输入Ctrl+C,直接终止它。进程会收到一个SIGINT信号。

图30:pstree观察进程树

图31:进程的中断

进程运行时输入ctrl+z使得进程中断。

图32:fg调用程序至前台

图33:杀死进程

6.7本章小结

通过对进程的学习和了解,我们熟悉了shell,fork,execve的相关概念,对异常和信号有了初步的认识,懂得了计算机通过并发执行激发性能,知道系统如何稳定运行并且始终保持高效。

(第6章1分)


7hello的存储管理

7.1 hello的存储器地址空间

1.逻辑地址

       程序经过编译后出现在汇编代码中的地址,逻辑地址用来指定一个操作数或者是一条指令的地址。是由一个段标识符加上一个指定段内相对地址的偏移量,表示为段标识符:段内偏移量。

2.线性地址

       逻辑地址到物理地址之间变换的中间层,在分段不见中逻辑地址就是段总的偏移地址,加上段的及地址就可以得到线性地址。

3.虚拟地址

       CPU启动保护模式之后,程序运行在虚拟地址空间中,虚拟地址空间是所有可能地址的集合,对于一个32位的机器而言,则集合中共有2^32种可能。

4.物理地址

       在存储器中以字节为单位存储信息,每一个字节单元与一个唯一的存储器地址一一对应,称为物理地址,又叫实际地址或者是绝对地址。物理地址对应了系统中实际的内存字节。

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

在段式存储管理中,将程序的地址空间划分为若干个段,这样每个进程有一个二维的地址空间。在前面所介绍的动态分区分配方式中,系统为整个进程分配一个连续的内存空间。而在段式存储管理系统中,则为每个段分配一个连续的分区,而进程中的各个段可以不连续地存放在内存的不同分区中。

程序加载时,操作系统为所有段分配其所需内存,这些段不必连续,物理内存的管理采用动态分区的管理方法。在为某个段分配物理内存时,可以采用首先适配法、下次适配法、最佳适配法等方法。在回收某个段所占用的空间时,要注意将收回的空间与其相邻的空间合并。段式存储管理也需要硬件支持,实现逻辑地址到物理地址的映射。

程序通过分段划分为多个模块,如代码段、数据段、共享段:可以分别编写和编译;可以针对不同类型的段采取不同的保护;可以按段为单位来进行共享,包括通过动态链接进行代码共享。这样做的优点是:可以分别编写和编译源程序的一个文件,并且可以针对不同类型的段采取不同的保护,也可以按段为单位来进行共享。

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

将程序的逻辑地址空间划分为固定大小的页,而物理内存划分为同样大小的页框。程序加载时,可将任意一页放人内存中任意一个页框,这些页框不必连续,从而实现了离散分配。该方法需要CPU的硬件支持,来实现逻辑地址和物理地址之间的映射。

在页式系统中进程建立时,操作系统为进程中所有的页分配页框。当进程撤销时收回所有分配给它的页框。在程序的运行期间,如果允许进程动态地申请空间,操作系统还要为进程申请的空间分配物理页框。操作系统为了完成这些功能,必须记录系统内存中实际的页框使用情况。操作系统还要在进程切换时,正确地切换两个不同的进程地址空间到物理内存空间的映射。这就要求操作系统要记录每个进程页表的相关信息。

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

线性地址到物理地址之间的转换通过使用分页机制完成。分页机制是指将虚拟内存分割为虚拟页的大小固定的块。

为判断虚拟页是否缓存在DRAM的某个地方,并确定虚拟页所在的物理页位置,因此需要一个页表。页表是一个页表条目(PTE)的数组,每个PTE由一个有效位和一个n位地址字段组成,有效位的设置与否表明了虚拟页是否被DRAM缓存。在地址翻译过程中,需要用到一个页表基址寄存器,指向当前页表。一个n位虚拟地址包含两个部分,一是p位的虚拟页面偏移,二是一个n-p位的虚拟页号。在虚拟页已被缓存的情况下,页面命中,MMU利用VPN来选择合适的PTE,将页表条目中的物理页号和虚拟地址中的虚拟页面偏移结合起来就可以得到一个物理地址。而如果虚拟页没有被缓存,那么就需要处理缺页,触发缺页异常,并将控制传递到缺页异常处理程序,缺页处理程序能够确定物理内存中的牺牲页,进而判断是否因被修改过而需要调出内存,完成牺牲页的替换之后,则调入新的页面,并更新内存中的PTE,最后返回到原来进程,将引起缺页的虚拟地址重新发给MMU,这次便变成了命中的情况。

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

得到物理地址之后,先将物理地址拆分成CT(标记)+CI(索引)+CO(偏移量),然后L1cache内部找,了L1里面以后,寻找物理地址检测是否命中,如果未能寻找到标记位为有效的字节(miss)的话就去二级和三级cache中寻找对应的字节,找到之后返回结果。到这里就是使用到我们的CPU的高速缓存机制了,使得机器在翻译地址的时候的性能得以充分发挥。

7.6 hello进程fork时的内存映射

在shell中输入命令./hello后,内核调用fork函数创建子进程,为hello程序的运行创建上下文,并分配一个与父进程不同的唯一的PID。为了给子进程创建虚拟内存,创建了当前进程的 mm_struct、区域结构和页表的原样副本。将这两个进程的每个页面都标记为只读,并将两个进程中的每个区域结构都标记为私有的写时复制。

7.7 hello进程execve时的内存映射

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

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

缺页故障:虚拟内存在DRAM缓存不命中即为缺页故障。

缺页中断处理:发生缺页故障时启动缺页处理程序

1、缺页处理程序确认出物理内存中的牺牲页,如果这个页已经被修改了,则把它换到磁盘。

2、缺页处理程序页面调入新的页面,并更新内存中的PTE

3、缺页处理程序返回到原来的进程,再次执行导致缺页的命令。

7.9动态存储分配管理

动态内存分配器维护着一个进程的虚拟内存区域,称为堆。系统之间细节不同,但是不失通用性,假设堆是一个请求二进制零的区域,它紧接在未初始化的数据区域后开始,并向上生长(向更高地址)。对于每个进程,内核维护着一个变量brk(读作“break”),它指向堆的顶部。

分配器风格:显式分配器和隐式分配器。

7.10本章小结

本章简要介绍了hello的存储地址空间。简单讲述了逻辑地址、虚拟地址、物理地址与线性地址的概念与转换方法,介绍了进程fork和execve时的内存映射的内容,描述了系统如何应对那些缺页异常,介绍了动态内存分配管理的方法

(第7章 2分)


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

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

(第8章1分)

结论

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

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

历程:

(1)编写hello.c的源程序

(2)预处理,将c文件调用的库与原本的c文件进行合并,得到hello.i文本文件

(3)编译:hello.i编译生成汇编语言文件hello.s

(4)汇编:hello.s汇编得到二进制可重定位目标文件hello.o

(5)链接:hello.o与其它调用库函数所在的可重定位目标文件和动态链接库链接生可执行文件hello,hello至此可以被加载入内存并运行。

(6)创建进程:终端shell调用fork函数,创建一个子进程,为程序的加载运行提供虚拟内存空间等上下文

(7)加载程序:shell调用execve函数,启动加载器映射虚拟内存,之后开始载入物理内存,在进入main函数

(8)访问内存:通过TLB和多级页表,实现虚拟内存和物理内存的翻译,进而访问计算机的存储结构,访问内存。

(9)IO:hello输入输出与外界进行交互,与Linux IO的抽象有关

(10)终止:hello被父进程回收,内核收回为其创建的所有信息。

非常遗憾这学期没有能够学习完CSAPP的全部内容,在众多课程的压力下,学习效率甚低,辜负了老师和助教的热情和付出,但总的来说,非常感谢一学期老师的陪伴与帮助,受益匪浅!

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


附件

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

hello 可执行文件

hello.elf  hello可执行文件的ELF格式

hello.o.elf  hello.o的 ELF 格式

hello.o 汇编之后的可重定位目标文件

hello.s 编译之后的汇编文件

hello.i 预处理后的文件

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值