ICS大作业论文-2021春

计算机系统

大作业

题 目 程序人生-Hello’s P2P

专 业 计算机类

学 号 1190201701

班 级 1903011

学 生 童彦澎

指 导 教 师 史先俊

计算机科学与技术学院

2021年5月

摘 要

本文从hello.c文件展开阐述,描绘了.c源文件从编译开始到被操作系统回收终止,这一hello文件短暂而又复杂的一生。文章基于深入理解计算机系统[1]一书组织,从各个方面尽可能细致地描绘对于计算机系统的浅显理解,内容包括但不限于:Editor
+ Cpp + Compiler + AS + LD + OS +
CPU/RAM/IO。从程序到进程,从零始,至零终,只有计算机系统知道hello曾经来过。

**关键词:**计算机系统;程序;进程

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

**
**

目 录

第1章 概述 - 4 -

1.1 Hello简介 - 4 -

1.2 环境与工具 - 4 -

1.3 中间结果 - 5 -

1.4 本章小结 - 5 -

第2章 预处理 - 6 -

2.1 预处理的概念与作用 - 6 -

2.2在Ubuntu下预处理的命令 - 6 -

2.3 Hello的预处理结果解析 - 7 -

2.4 本章小结 - 8 -

第3章 编译 - 9 -

3.1 编译的概念与作用 - 9 -

3.2 在Ubuntu下编译的命令 - 9 -

3.3 Hello的编译结果解析 - 10 -

3.3.1 函数调用 - 10 -

3.3.2 for循环、if分支 - 12 -

3.3.3 变量的存储形式 - 13 -

3.4 本章小结 - 13 -

第4章 汇编 - 14 -

4.1 汇编的概念与作用 - 14 -

4.2 在Ubuntu下汇编的命令 - 14 -

4.3 可重定位目标elf格式 - 15 -

4.4 Hello.o的结果解析 - 17 -

4.5 本章小结 - 18 -

第5章 链接 - 20 -

5.1 链接的概念与作用 - 20 -

5.2 在Ubuntu下链接的命令 - 20 -

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

5.4 hello的虚拟地址空间 - 22 -

5.5 链接的重定位过程分析 - 23 -

5.6 hello的执行流程 - 25 -

5.7 Hello的动态链接分析 - 25 -

5.8 本章小结 - 26 -

第6章 hello进程管理 - 28 -

6.1 进程的概念与作用 - 28 -

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

6.3 Hello的fork进程创建过程 - 28 -

6.4 Hello的execve过程 - 29 -

6.5 Hello的进程执行 - 30 -

6.6 hello的异常与信号处理 - 32 -

6.7本章小结 - 36 -

第7章 hello的存储管理 - 37 -

7.1 hello的存储器地址空间 - 37 -

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

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

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

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

7.6 hello进程fork时的内存映射 - 41 -

7.7 hello进程execve时的内存映射 - 41 -

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

7.9动态存储分配管理 - 43 -

7.10本章小结 - 46 -

第8章 hello的IO管理 - 47 -

8.1 Linux的IO设备管理方法 - 47 -

8.2 简述Unix IO接口及其函数 - 47 -

8.3 printf的实现分析 - 48 -

8.4 getchar的实现分析 - 48 -

8.5本章小结 - 49 -

结论 - 50 -

附件 - 52 -

参考文献 - 53 -

第1章 概述

1.1 Hello简介

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

程序员编写好一个hello.c文件后,就将其交给编译器处理。

  1. cpp对其进行预处理,进行宏替换等,生成hello.i文件。

  2. ccl对它进行编译,将文本代码编译成汇编代码,汇编代码既具备较好的可读性,又便于转换为机器代码。生成Hello.s文件。

  3. as对它进行汇编,将汇编代码转化为机器代码,生成hello.o文件。

  4. hello.o文件还未包含相应库函数等的定义以及一些必要的系统代码,ld将其与其他必要的.o文件链接在一起,形成一个可执行的、可加载到内存运行的hello.out文件(Linux下)。

  5. 在shell中./hello,shell解析命令行,代表程序员执行了hello程序,创建了hello这个进程,自此,hello程序运行在了PC机上。

  6. 用户可以采用特定的方式给这个进程发送信号——CTRL+C、CTRL+V等,一旦进程被终止,父进程(shell)有义务对其进行回收,防止其称为僵尸进程,占用宝贵的内存资源,具体过程为:shell调用fork函数创建一个子进程,在子进程中调用execve加载hello这一程序,自此,hello开始成为一个独立的进程开始运行,hello由于各种原因(return、异常、信号)终止后,父进程(shell)调用waitpid函数,对齐进行回收,回收以后,这个进程便不复存在,hello也就在PC上彻底结束了它的一生。

  7. 在hello运行的过程中,涉及到代码与相关数据的加载,这是基于计算机存储体系的:采用Cache技术,很好地兼顾到了容量与速度,做到了二者兼而有之。

  8. 虚拟内存技术实现了对内存的有效管理:在hello进程中,所有信息均存储在虚拟地址空间中,而通过虚拟内存技术,将虚拟地址映射到物理地址。虚拟内存技术也采用了一些十分重要的技术进行优化:TLB——快表作为页表的缓存;多级页表大大减少了页表在内存中的大小,释放了稀缺的内存资源。

1.2 环境与工具

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

硬件环境:X64 CPU;2GHz;2G RAM;256GHD Disk 以上

软件环境:Windows7 64位以上;VirtualBox/Vmware 11以上;Ubuntu 16.04 LTS
64位/优麒麟 64位 以上;VSCode。

1.3 中间结果

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

Hello.c:c源文件

Hello.i:预处理后.i文件

Hello.s:汇编文件

Hello.o:可重定位目标文件

Hello.out:可执行文件(Linux下)

1.4 本章小结

Hello P2P、020概述以及相关环境、文件描述。

(第1章0.5分)

第2章 预处理

2.1 预处理的概念与作用

概念:预处理器(Preprocessor)分析预处理指令(包括#include头文件和#define宏定义等)以及去除源代码中的注释的过程。

作用:将.c以及.h文件输出为.i文件,例如#include
<stdio.h>在预处理阶段,将头文件中的内容直接插入程序文本中,以及删去注释等等,做诸如此类的操作,得到另一个c程序,以.i为文件扩展名。

2.2在Ubuntu下预处理的命令

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-69lyEL7N-1624804986476)(media/fd6853028b0324403bd2e254f65faff8.png)]

图 1 预处理

采用-E 参数,让编译过程停留在预处理阶段,或是采用cpp hello.c > hello.i
命令,调用cpp预处理器单步进行。可以看到文件夹中生成了hello.i文件。

2.3 Hello的预处理结果解析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zl5vni5K-1624804986478)(media/b3fb2cb10af16f83c600728271350f95.png)]

图 2 .i文件示意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zpUpSict-1624804986481)(media/8979b3abd81b9945a9fbb3233ab9d33d.png)]

图 3 .i文件示意

可以看到.i文件中定义了大量结构体(stdio头文件的引入)以及最后的main函数部分。

2.4 本章小结

预处理是编译一个c程序的第一步,也是不可缺失的一步,主要完成宏替换、头文件的引入以及注释的去除,为接下来的编译过程做准备。

(第2章0.5分)

第3章 编译

3.1 编译的概念与作用

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

概念:编译器将.i文本文件翻译成.s文本文件,它包含一个汇编语言程序的过程。

作用:将c语言程序翻译成汇编语言程序,为不同的高级语言提供相同的输出语言,便于机器语言的转换。

3.2 在Ubuntu下编译的命令

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

应截图,展示编译过程!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U93IO0CZ-1624804986482)(media/a23858d938d3c405eeac030a63e52a21.png)]

图 4 .s文件

采用-S 参数,让编译器生成.s文件,看到生成hello.s文件。

3.3 Hello的编译结果解析

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

3.3.1 函数调用

调用时栈帧变化:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gdBwnneM-1624804986484)(media/cd7b63e2edb5cb52e2af70256fb086ef.png)]

对rbp寄存器做保护,而后增长栈顶为局部变量等预留空间。

参数传递:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oJkYwmhJ-1624804986485)(media/d145f0844b5f64300c00319da81dd2d0.png)]

对应的c语言语句为:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2HMLVBFQ-1624804986486)(media/fb43c1c8f498a195af4718e98b847461.png)]

可以看到argc参数采用edi传递,进一步调用puts以及exit的函数也是采用edi传参,在Linux64位系统下,参数传递采用寄存器与堆栈相结合,参数个数大于特定寄存器个数即采用堆栈传参;32bit系统下,均采用堆栈传参。

For循环中的printf函数调用:

可以看到对应的汇编代码为:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EO1NFwlT-1624804986487)(media/4231052614b0610418635932d34b7428.png)]

图 5 main汇编代码

可以看到为了调用printf函数,传递了三个参数,格式化字符串用rdi,argv[1]用rsi传递,argv[2]用rdx传递。Atoi,sleep,getchar函数的参数调用类似,不赘述。

在函数调用(call语句执行)之前,应先将返回地址压栈。

3.3.2 for循环、if分支

对应汇编代码:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BVo93vyP-1624804986488)(media/7f6a98089eba94518089ff54aadd259e.png)]

图 6 对应汇编代码

可以看到局部变量i存在栈中,rbp-4。通过i<=7的条件跳转实现for循环。类似地,分支语句也通过条件跳转实现。

3.3.3 变量的存储形式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3VH1yIMN-1624804986488)(media/ce8c5a34ef99adc50cd1be2742a32f99.png)]

图 7 源代码

Main函数的变量有局部变量i,argc,argv,字符串字面量(两个格式化字符串),下面分别阐述它们的存储形式:

局部变量:初次引用为movl $0,rbp-4,即在栈中存储。Argc,初次引用为:

movl %edi, -20(%rbp)

argv初次引用:

movq %rsi, -32(%rbp)

可以看到作为main函数的参数以寄存器传递,上述分析中有提及。

两个字符串字面量的存储形式:

leaq .LC0(%rip), %rdi

可以看到是传递字符串的地址进寄存器,即字符串在汇编语言中通过地址引用。

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

3.4 本章小结

编译是将文本代码转变为机器语言中的关键一步,将.i文件编译为.s汇编文件,从文本代码变为汇编语言,而汇编语言是各种高级语言的统一输出,为进一步汇编为机器代码提供极大的便利。

(第3章2分)

第4章 汇编

4.1 汇编的概念与作用

概念:汇编器将.s文件翻译成机器语言指令,把这些指令打包成可重定位目标程序(.o文件)的过程。

作用:将汇编程序转变为机器指令,便于计算机存储与执行(计算机是二进制的)。

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

4.2 在Ubuntu下汇编的命令

应截图,展示汇编过程!

汇编命令:-c 参数,或者as hello.s –o hello.o 直接调用汇编器。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UlEhh91G-1624804986489)(media/95637bc7c5bcd418d35e8fd18e945ec4.png)]

图 8 汇编命令

可以看到汇编后产生了hello.o文件。

4.3 可重定位目标elf格式

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YVpzVtC4-1624804986490)(media/2d5f34d0c7d9254b6864a5554bad9fbd.png)]

图 9 ELF头

从ELF头中可以看到hello.o是可重定位的目标文件,还能获得入口地址、节头起始位置、节头大小、ELF头大小……

重定位节信息:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gRE9j9oA-1624804986493)(media/0ceb559025f15afe803507882138d8cb.png)]

图 10 重定位节信息

可以看到puts、exit、sleep等系统函数等待链接以及重定位,给出了每个条目相应的偏移以及相关信息和种类。.rodata段部分内容也是重定位条目之一。

符号表:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-20cW4jZ8-1624804986494)(media/34359275bd45026f8a681fd17bf0f4f9.png)]

图 11 符号表

从符号表中可以看到:main、puts等系统函数被符号解析,而main函数中没有全局变量(与static局部变量),局部变量在栈中,不需要符号解析。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hq7WlcWP-1624804986494)(media/f49f953b928666493545a47909f4a7bc.png)]

图 12 节头信息

从节头中可以看到.text节存放代码,有相应size;.rela.text中存放.text节位置列表,用于重定位,.rodata只读数据段存放格式化字符串,.symtab符号表中存放相关符号信息。

4.4 Hello.o的结果解析

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

.text段反汇编如图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PZjCLupW-1624804986495)(media/bda8884f178f806551716fab7ba06f29.png)]

图 13 text段反汇编

Hello.s如图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2HqfK6JO-1624804986496)(media/c4034b1d8207383d3f5e6c2eb435f4eb.png)]

图 14 汇编文件

对照分析:

反汇编得到的汇编代码与hello.s并无太大区别,可以看到,对于字符串的访问以及puts、getchar、exit等系统函数的调用包含了重定位信息。

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

机器语言指令由操作码与操作数构成,操作数往往是寄存器代码或者是一些常数字,代表地址或是一些常数。操作码映射为汇编语言的add等功能,可以称为功能码,操作数映射为寄存器或是一些地址、常数等,汇编语言中的操作数可以是寄存器,例如mov
rsp,rbp,在机器语言中寄存器就被编码进入指令当中,以寄存器ID的形式体现。分支转移通过jmp实现,而jmp在机器指令中的操作码包含代码部分与功能部分,以此来区分jl、jg、je等等;函数调用通过call来实现,操作码较为单一为80,操作数即为dst目的地址。

4.5 本章小结

汇编将.s文件翻译为.o可重定位目标文件,将文本文件转化为二进制文件,便于计算机执行,但并未经过链接,代码及数据段是可以重定位的,并不能执行,是生成可执行程序前的重要一步。

(第4章1分)

第5章 链接

5.1 链接的概念与作用

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

概念:以一组可重定位目标文件为输入,生成一个完全链接的、可加载和运行的可执行目标文件的过程。

作用:将各类库函数及头文件中的函数都链接进.o文件中,生成可执行的.exe/.out文件。链接主要完成符号解析以及重定位两大功能。

5.2 在Ubuntu下链接的命令

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-25V4qhHM-1624804986497)(media/39f74a8c8048ab4b01f2615fbaab7182.png)]

图 15 链接命令

可以看到成功生成.out文件并执行。

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RV1LDlyP-1624804986498)(media/e0036b66c188f90309f171135e924898.png)]

图 16 ELF头

从ELF头中可以看到,该ELF文件是一个可执行文件,数据采用补码存储,小端序,文件的入口地址是4010f0,以及一些相关的size信息。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TYyikoDg-1624804986499)(media/66a20a37bf3446f5da6c6ca170656f9f.png)]

图 17 节头信息

从节头表中可以看到各段的大小以及起始位置。

5.4 hello的虚拟地址空间

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

通过edb看到虚拟地址空间从0x401000开始,对应5.3中的.init节;同理,.text节应从0x4010f0开始,如图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mllluEOE-1624804986500)(media/8778b5f965f9f7726e69731d2bb53ff0.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DL7F0czt-1624804986500)(media/f74be608442be47848baf2164b4962d0.png)]

图 18 虚拟内存信息

数据段等也同理分析,略去。

5.5 链接的重定位过程分析

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DIAWNTrH-1624804986501)(media/9d6b78ce8863667c9ecd966a654c00c9.png)]

图 19 反汇编代码

  1. 可以看到,最大的不同是,对于库函数的调用的地址已经重定位,而不是.o文件中以0填充。

  2. 其次,hello的反汇编中包含了大量的函数以及一些节的汇编代码。

    如图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TTXuEJh9-1624804986502)(media/a712b8d81a2a8fa63c9c0611b8988532.png)]

图 20 反汇编代码

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

.o文件的重定位项目:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-khzbZkvL-1624804986502)(media/0ceb559025f15afe803507882138d8cb.png)]

图 21 重定位项目

重定位过程:

(1)重定位节和符号定义。链接器将所有类型相同的节合并在一起后,这个节就作为可执行目标文件的节。然后链接器把运行时的内存地址赋给新的聚合节,赋给输入模块定义的每个节,以及赋给输入模块定义的每个符号,当这一步完成时,程序中每条指令和全局变量都有唯一运行时的地址。

(2)重定位节中的符号引用。这一步中,连接器修改代码节和数据节中对每个符号的引用,使他们指向正确的运行时地址。执行这一步,链接器依赖于可重定位目标模块中称为的重定位条目的数据结构。

(3)重定位条目:当汇编器遇到对最终位置未知的目标引用时,它就会生成一个重定位条目。代码的重定位条目放在.rel.text,如上图所示。

(4)重定位条目数据结构:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZV4bL3i4-1624804986503)(media/b22c28d1b8ada8a9991e698599d489b1.png)] (5)重定位算法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ipj82ltB-1624804986504)(media/7b2c441b7e64e2ef19990ccf61c8a115.png)]

5.6 hello的执行流程

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

Ld-2.31.sohello!_start__libc_start_mainlibc-2.31.so!_cxa_atexithello!_libc_csu_initlibc-2.31.so!_setjmphello!mainlibc-2.31.so!exit

5.7 Hello的动态链接分析

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

PLT:PLT是一个数组,其中每个条目是16字节代码。PLT[0]是一个特殊条目,它跳转到动态链接器中。每个被可执行程序调用的库函数都有它自己的PLT条目。每个条目都负责调用一个具体的函数。

GOT:GOT是一个数组,其中每个条目是8字节地址。和PLT联合使用时,GOT[O]和GOT[1]包含动态链接器在解析函数地址时会使用的信息。GOT[2]是动态链接器在1d-linux.so模块中的入口点。其余的每个条目对应于一个被调用的函数,其地址需要在运行时被解析。每个条目都有一个相匹配的PLT条目。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UQHVZxoR-1624804986504)(media/0e7ff3d198363076b79d9ce5cc76ea44.png)]

根据ELF文件可知got的起始地址0x404000。

可以看到dl_init前地址偏移8处为0:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DeLLbV3u-1624804986505)(media/76bc194be50baa8fd1eb07428b46828e.png)]

在_start执行前,got节已经有了内容:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gUlKtWTI-1624804986506)(media/e2ffa8a74ce51ceca11e77f403f3f961.png)]

图 22 虚拟内存信息

5.8 本章小结

链接的两大功能:符号解析与重定位,是生成可执行程序前可以说是必不可缺的一个过程,保证了.o文件能与各类相关.o文件以及操作系统代码能完全链接,生成可执行文件。

(第5章1分)

第6章 hello进程管理

6.1 进程的概念与作用

概念:进程是一个执行中的程序的实例,每一个进程都有它自己的地址空间,一般情
况下,包括文本区域、数据区域、和堆栈。文本区域存储处理器执行的代码;数
据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储区着活动
过程调用的指令和本地变量。

作用:进程为用户提供了以下假象:

(1)
我们的程序好像是系统中当前运行的唯一程序一样,我们的程序好像是独占的使用处理器和内存。

(2)
处理器好像是无间断的执行我们程序中的指令,我们程序中的代码和数据好像是系统内存中唯一的对象。

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

Shell是一个交互型应用级程序,代表用户运行其他程序(是命令行解释器,以用户态方式运行的终端进程)。

处理流程:

(1)终端进程读取用户由键盘输入的命令行。

(2)解析命令行字符串,获取命令行参数,并构造传递给execve的argv向量

(3)检查第一个(首个、第0个)命令行参数是否是一个内置的shell命令;若是内置命令,立刻执行。

(4)如果不是内部命令,调用fork( )创建新进程/子进程

(5)在子进程中,用步骤2获取的参数,调用execve( )执行指定程序。

(6)如果用户没要求后台运行(命令末尾没有&号),则shell使用waitpid(或wait函数)等待作业终止后返回。

(7)如果用户要求后台运行(如果命令末尾有&号),则shell返回;

6.3 Hello的fork进程创建过程

终端程序通过调用fork()函数创建一个子进程,子进程得到与父进程完全相同但是独立的一个副本,包括代码段、段、数据段、共享库以及用户栈。子进程还获得与父进程任何打开文件描述符相同的副本,父进程和子进程最大的不同是他们的PID是不同的,以及数据是独立的。父进程与子进程是并发运行的独立进程,内核能够以任意方式交替执行它们的逻辑控制流的指令。

我们./hello并输入相应的参数,[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7fYCEMdU-1624804986507)(media/efd6219bc4a3aa464f52da99744c7745.png)]

图 23 命令行演示

Shell解析不是内置命令,加载运行外部程序,shell立刻fork一个进程,创建了一个子进程。

6.4 Hello的execve过程

当创建了一个子进程之后,子进程调用exceve函数在当前子进程的上下文加载并运行一个新的程序即hello程序,加载并运行需要以下几个步骤:

(1)删除已存在的用户区域。删除当前进程虚拟地址的用户部分中已存在的区域结构。

(2)映射私有区域。为新程序的代码、数据、bss和栈区域创建新的区域结构。所有这些区域结构都是私有的,写时复制的。虚拟地址空间的代码和数据区域被映射为hello文件的.txt和.data区。bss区域是请求二进制零的,映射匿名文件,其大小包含在hello文件中。栈和堆区域也是请求二进制零的,初始长度为零。

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

(4)设置程序计数器(PC)。exceve做的最后一件事就是设置当前进程的上下文中的程序计数器,使之指向代码区域的入口点。下一次调用这个进程时,它将从这个入口点开始执行。Linux将根据需要换入代码和数据页面。

进程虚拟内存示意:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P6V14RpW-1624804986507)(media/afc64d61aa2959808f852e852ad883a9.png)]

在hello中,shell进行fork以后子进程调用execve,加载了hello进程。

6.5 Hello的进程执行

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

1.并发流:一个逻辑流的执行时间与另一个流重叠,成为并发流,这两个流成为并发的运行。多个流并发的执行的一般现象成为并发。

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

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

4.上下文信息:上下文就是内核重新启动一个被抢占的进程所需要的状态,它由
通用寄存器、浮点寄存器、程序计数器、用户栈、状态寄存器、内核栈和各种内
核数据结构等对象的值构成。

5.上下文切换:当内核选择一个新的进程运行时,则内核调度了这个进程。在内核调度了一个新的进程运行后,它就抢占当前进程,并使用一种称为上下文切换的机制来将控制转移到新的进程:

1) 保存以前进程的上下文

2)恢复新恢复进程被保存的上下文,

3)将控制传递给这 个新恢复的进程 ,来完成上下文切换。

Hello进程的执行:子进程调用execve函数之后,hello进程已被装载。首先,hello运行在用户模式下,输出hello
1190201701
童彦澎,然后hello调用sleep函数之后进程陷入内核模式,内核不会选择什么都不做等待sleep函数调用结束,而是处理休眠请求主动释放当前进程,并将hello进程从运行队列中移出加入等待队列,定时器开始计时,内核进行上下文切换将当前进程的控制权交给其他进程,当定时器到时发送一个中断信号,此时进入内核状态执行中断处理,将hello进程从等待队列中移出重新加入到运行队列,成为就绪状态,hello进程就可以继续进行自己的控制逻辑流了。示意图如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fNoztcaa-1624804986508)(media/2a483dd3a4807cc8de73d46fc38c8330.png)]

图 24 程序运行示意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yX2TgpwA-1624804986509)(media/80f762d1aeffd60042295d397c8df714.png)]

6.6 hello的异常与信号处理

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

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

异常有以下四类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4EBfIvP2-1624804986509)(media/1c48b87873b59f2bce8870673f229cfe.png)]

在hello中都可能出现:

  1. 中断:计时器发现进程已经执行了一定时间片,向进程发送了中断信号,进程被中断;

  2. 陷阱:sleep函数执行时,执行一些系统调用,发生有意的异常。

  3. 虚拟内存中页面未缓存时发生缺页中断,即故障异常。

  4. 磁盘损坏、DRAM奇偶校验位错误,发生终止异常。

    这四种异常都属于较为底层的异常,处理机制又内核调用相应的异常处理程序处理。

    常见信号如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KUdR1Ygq-1624804986510)(media/df4ce302d662d2188776055dfe5f2bac.png)]

图 25 常见信号

在hello中可能出现以下不完全列举的几种信号:

  1. SIGINT

    处理方法:杀死hello进程。

  2. SIGTSTP

    处理方法:挂起hello进程,直到被SIGCONT信号唤醒。

  3. SIGCHLD

    Hello进程被停止或终止时,发送一个信号给父进程,父进程对该信号的处理是回收子进程,若只是停止则忽略。

命令测试:

  1. 不停乱按:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x2cei6Wu-1624804986511)(media/a756166563cadd565edfa5a5255e4e24.png)]

    可以看到getchar读入了一个字符串,其余当作命令行参数执行。

  2. CTRL+C:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xv7VbIfk-1624804986513)(media/0d54c59998544a51876890cfb5db4719.png)]

    进程终止

  3. CTRL+Z:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-THyLLcwq-1624804986514)(media/501eec378bcf4ee1ba7f0e60ee5ae959.png)]

  4. jobs:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aGiAhehj-1624804986514)(media/755feb42f61656080fcd0d2eb153842b.png)]

  5. fg:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TQHpUVnq-1624804986515)(media/07fc2cef2d4431039b770524de7dbb7a.png)]

    可以看到将hello又变成前台进程后,继续运行,

  6. kill:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QckE6OGG-1624804986516)(media/bfcb9d726da30159eb30cb6930d7ecde.png)]

    发送一个SIGKILL信号给hello进程,看到进程被杀死。

6.7本章小结

进程是计算机科学中最深刻、最成功的概念之一,进程这一抽象概念便于操作系统进行程序之间的调度,是各种异常处理的基础,也是联系内存、处理器、IO的重要概念。

(第6章1分)

第7章 hello的存储管理

7.1 hello的存储器地址空间

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

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

线性地址:也叫虚拟地址,和逻辑地址类似,也是一个不真实的地址,如果逻辑地址是对应的硬件平台段式管理转换前地址的话,那么线性地址则对应了硬件也是内存的转换前地址。

虚拟地址:也就是线性地址。

物理地址:用于内存芯片级的单元寻址,与处理器和CPU链接的地址总线相对应。可以直接把物理地址理解成插在机器上那根内存本身,把内存看成一个从0字节一直到最大容量逐字节的编号的大数组,然后把这个数组叫做物理地址,但是事实上,这只是一个硬件提供给软件的抽象,内存的寻址方式并不是这样。

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

实模式下: 逻辑地址CS:EA =物理地址CS*16+EA

保护模式下:以段描述符作为下标,到GDT/LDT表查表获得段地址,

段地址+偏移地址=线性地址。

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

使用虚拟寻址,CPU通过生成一个虚拟地址来访问主存,这个虚拟地址被送到内存之前首先转换为适当的物理地址。将一个虚拟地址转换为物理地址叫做地址翻译,需要CPU硬件和操作系统之间的紧密合作。CPU芯片上叫做内存管理单元(MMU)的硬件,利用主存中的查询表来动态翻译虚拟地址。

虚拟地址作为到磁盘上存放字节的数组的索引,磁盘上的数组内容被缓存在主存中。同时,磁盘上的数据被分割成块,这些块作为磁盘和主存之间的传送单元。虚拟内存分割被成为虚拟页。物理内存被分割为物理页,物理页和虚拟页的大小是相同的。

任意时刻虚拟页都被分为三个不相交的子集:

未分配的:VM系统还未分配的页

缓存的:当前已经缓存在物理内存的已分配页

未缓存的:当前未缓存在物理内存的已分配页

每次将虚拟地址转换为物理地址,都会查询页表来判断一个虚拟页是否缓存在DRAM的某个地方,如果不在DRAM的某个地方,通过查询页表条目可以知道虚拟页在磁盘的位置。页表将虚拟页映射到物理页。如图所示,页表就是一个页表条目的数组,每一个页表条目是由一个有效位和一个n为地址字段组成。有效位表明虚拟页是否缓存在DRAM中,n位地址字段是物理页的起始地址或者虚拟页在磁盘的起始地址。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xiA3iA57-1624804986517)(media/7915e3ed6ec60c53b40c5784e5acfdd2.png)]

n位的虚拟地址包含两个部分:一个p位的虚拟页面偏移(VPO),一个n-p位的虚拟页号(VPN),MMU利用VPN选择适当的PTE,例如VPN
0选择PTE
0。根据PTE,我们知道虚拟页的信息,如果虚拟页是已缓存的,直接将页表条目的物理页号和虚拟地址的VPO串联起来就得到一个相应的物理地址。这里的VPO和PPO是相同的。如果虚拟页是未缓存的,会触发一个缺页故障。调用一个缺页处理子程序将磁盘的虚拟页重新加载到内存中,然后再执行这个导致缺页的指令。

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

假定:虚拟地址空间 48 位,物理地址空间 52 位,页表大小 4KB,4 级页表。TLB 4 路
16 组相联。CR3 指向第一级页表的起始位置(上下文一部分)。 分析:由一个页表大小
4KB,一个 PTE 条目8B,共 512 个条目,使 用 9 位二进制索引,一共 4 个页表共使用
36 位二进制索引,所以 VPN 共 36 位, 因为 VA 48 位,所以 VPO 12 位;因为 TLB 共
16 组,所以 TLBI 需 4 位,因为 VPN 36 位,所以 TLBT 32 位。

如图所示,CPU 产生虚拟地址 VA,VA 传送给 MMU,MMU 使用前 36 位 VPN 作为 TLBT(前
32 位)+TLBI(后 4 位)向 TLB 中匹配,如果命中,则得到 PPN (40bit)与
VPO(12bit)组合成 PA(52bit)。 如果 TLB 中没有命中,MMU 向页表中查询,CR3
确定第一级页表的起始地 址,VPN1(9bit)确定在第一级页表中的偏移量,查询出
PTE,如果在物理内存
中且权限符合,确定第二级页表的起始地址,以此类推,最终在第四级页表中查询到
PPN,与 VPO 组合成 PA,并且向 TLB 中添加条目。如果查询 PTE
的时候发现不在物理内存中,则引发缺页故障。如果发现权限不够,则引发段错误。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FtMDGhEc-1624804986518)(media/445d561cd72fcda89d84f2ebb648c337.png)]

图 26 Intel虚拟内存机制示意

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

K级存储做k+1级存储的cache,这里以L1Cache为例进行分析:

由于L1Cashe有64组,所以组索引位s为6,每组有8个高速缓存行,由于每个块的大小为64B,所以块偏移为为6,因此标记位为52-6-6=40位。

因此L1Cashe的物理访存大致过程如下:

(1)
组选择取出虚拟地址的组索引位,将二进制组索引转化为一个无符号整数,找到相应的组

(2)
行匹配把虚拟地址的标记为拿去和相应的组中所有行的标记位进行比较,当虚拟地址的标记位和高速缓存行的标记位匹配时,而且高速缓存行的有效位是1,则高速缓存命中。

(3)
字选择一旦高速缓存命中,我们就知道我们要找的字节在这个块的某个地方。因此块偏移位提供了第一个字节的偏移。把这个字节的内容取出返回给CPU即可

(4)不命中如果高速缓存不命中,那么需要从存储层次结构中的下一层取出被请求的块,然后将新的块存储在组索引位所指示的组中的一个高速缓存行中。一种简单的放置策略如下:如果映射到的组内有空闲块,则直接放置,否则组内都是有效块,产生冲突(evict),则采用最近最少使用策略
LRU或者是LFU策略(一段时间周期内最不频繁访问) 进行替换。如图所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3B0T4sg4-1624804986520)(media/88578dbd1f3cd8677bded06b8ea843ca.png)]

7.6 hello进程fork时的内存映射

当 fork 函数被 shell 进程调用时,内核为新进程创建各种数据结构,并分配给
它一个唯一的 PID,为了给这个新进程创建虚拟内存,它创建了当前进程的
mm_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 做的最后一件事情就是设置当前进程
上下文的程序计数器,使之指向代码区域的入口点。

虚拟内存示意如图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SJcMPyBE-1624804986521)(media/f29d25b94c4a6350721a8d167702ef72.png)]

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

缺页故障:当指令引用一个相应的虚拟地址,而与改地址相应的物理页面不再内存中,会触发缺页故障。通过查询页表PTE可以知道虚拟页在磁盘的位置。缺页处理程序从指定的位置加载页面
到物理内存中,并更新PTE。然后控制返回给引起缺页故障的指令。当指令再次执行时,相应的物理页面已经驻留在内存中,因此指令可以没有故障的运行完成。故障处理具体流程如图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xWoGGTSj-1624804986522)(media/5b345dbbc75925800a7ee283f7c0a150.png)]

7.9动态存储分配管理

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

动态内存分配器维护者一个进程的虚拟内存区域,成为堆。(如图所示),

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mLzrviI7-1624804986523)(media/2acd5826f0b63fc12c59863156d7ec3f.png)]

分配器将堆视为一组不同的大小的块的集合来维护。每个块就是一个连续的虚拟内存片,要么是已分配的,要么是空闲的。分配器有两种基本风格。两种风格都是要求显式地分配块。

(1)
显式分配器:要求应用显式的释放任何已分配的块。例如C标准库提供一个叫做malloc程序包的显式分配器。

(2)
隐式分配器:要求分配器检测一个已分配块何时不再被程序使用,那么就释放这个块。隐式分配器也叫垃圾收集器。

显式分配器的实现方式:

  1. 隐式空闲链表:

    隐式空闲链表区别块的边界、已分配块和空闲块的方法如图所示

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3hA67O2u-1624804986525)(media/26651ecc31cdcf20b59554c484cecd08.png)]

    这种情况下,一个块是由一个字的头部、有效载荷,以及可能的填充组成。头部编码了这个块的大小(包括头部和所有的填充),以及这个块是已分配的还是空闲的。块的头最后一位指明这个块是已分配的还是空闲的。

    头部后面是应用malloc时请求的有效载荷。有效载荷后面是一片不使用的填充块,其大小可以是任意的。块的格式如图7.9.3所示,空闲块通过头部块的大小字段隐含的连接着,所以我们称这种结构就隐式空闲链表。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WPtiZFRQ-1624804986525)(media/1aa91806f0e16cea569a970616c74b24.png)]

    (1)放置已分配的块当一个应用请求一个k字节的块时,分配器搜索空闲链表。查找一个足够大可以放置所请求的空闲块。分配器搜索方式的常见策略是首次适配、下一次适配和最佳适配。

    (2)分割空闲块一旦分配器找到一个匹配的空闲块,就必须做一个另策决定,那就是分配这个块多少空间。分配器通常将空闲块分割为两部分。第一部分变为了已分配块,第二部分变为了空闲块。如图7.9.4所示。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vQgYQFVT-1624804986526)(media/51c4ddcd0aa278dd8b3ffb62a5c4271d.png)]

    (3)获取额外堆内存如果分配器不能为请求块找到空闲块,一个选择是合并那些在物理内存上相邻的空闲块,如果这样还不能生成一个足够大的块,分配器会调用sbrk函数,向内核请求额外的内存。

    (4)合并空闲块合并的情况一共分为四种:前空后不空,前不空后空,前后都空,前后都不空。对于四种情况分别进行空闲块合并,我们只需要通过改变头部的信息就能完成合并空闲块。Knuth提出了一种采用边界标记的技术快速完成空闲块的合并。如图所示

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VYO1GCAh-1624804986527)(media/b457ce4f66b56a71b8c8dcb62e89c06f.png)]

  2. 显式空闲链表:

    显示空闲链表是将空闲块组织为某种形式的显示数据结构。如图7.9.6所示。堆被组织为一个双向空闲链表,在每个空闲块中,都包含一个前驱和后继的指针。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IyMg06HG-1624804986527)(media/0a4962bc10d5f16663f23569fba01747.png)]

    使用双向链表而不是隐式空闲链表,使首次适配的分配时间从块总数的线
    性时间减少到了空闲块数量的线性时间。

    一种方法使用后进先出的顺序维护链表,将新释放的块在链表的开始处。使用LIFO的顺序和首次适配的放置策略,分配器会最先检查最近使用过
    的块,在这种情况下,释放一个块可以在线性的时间内完成,如果使用了边界
    标记,那么合并也可以在常数时间内完成。

    按照地址顺序来维护链表,其中链
    表中的每个块的地址都小于它的后继的地址,在这种情况下,释放一个块需要
    线性时间的搜索来定位合适的前驱。平衡点在于,按照地址排序首次适配比 LIFO
    排序的首次适配有着更高的内存利用率,接近最佳适配的利用率。

7.10本章小结

存储不仅采用了cache技术,使存储有了容量与速度的结合,更采用了虚拟内存技术,完成了虚拟地址到物理地址的转换,实现进程私有地址空间的抽象。

(第7章 2分)

第8章 hello的IO管理

8.1 Linux的IO设备管理方法

设备的模型化:文件
一个Linux文件就是一个m字节的序列:B0,B1,B2……Bm

设备管理:unix io接口

所有的 IO 设备(如网路、磁盘、终端)都被模型化为文件,而所有的输入和输出都被
当做对相应文件的读和写来执行,这种将设备优雅地映射为文件的方式,允许 Linux
内核引出一个简单低级的应用接口,称为 Unix
I/O,这使得所有的输入和输出都被当做相应文件的读和写来执行。

8.2 简述Unix IO接口及其函数

Unix I/O 接口:

(1)打开文件。一个应用程序通过要求内核打开相应的文件,来宣告它想 要访问一个 I/O
设备,内核返回一个小的非负整数,叫做描述符,它在后续对此文件的所有操作中标识这个文件,内核记录有关这个打开文
件的所有信息。

(2)Shell 创建的每个进程都有三个打开的文件:标准输入,标准输出,标准错误。

(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) ,进程通过调用 open 函
数来打开一个存在的文件或是创建一个新文件的。 open函数将filename
转换为一个文件描述符,并且返回描述符数字,返回的描述符总是在进程中当前没有打开的最小描述符,flags
参数指明了进程打算如何访 问这个文件,mode 参数指定了新文件的访问权限位。

(2)int close(fd),fd是需要关闭的文件的描述符,close返回操作结果。

(3) ssize_t read(int fd,void *buf,size_t n),read 函数从描述符为fd的当前文
件位置赋值最多 n 个字节到内存位置 buf。返回值-1 表示一个错误,0 表示
EOF,否则返回值表示的是实际传送的字节数量。

4) ssize_t wirte(int fd,const void *buf,size_t n),write 函数从内存位置 buf
复制至多 n 个字节到描述符为 fd 的当前文件位置。

8.3 printf的实现分析

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

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

Printf函数体:

1. static int printf(const char *fmt, …)

2. {

3. va_list args;

4. int i;

5. va_start(args, fmt);

6. write(1,printbuf,i=vsprintf(printbuf, fmt, args));

7. va_end(args);

8. return i;

9.}

在printf中调用系统函数write(buf,i)将长度为i的buf输出,在write函数中,将栈中参数放入寄存器,ecx是字符个数,ebx存放第一个字符地址,write中含系统调用:syscall将字符串中的字节从寄存器中通过总线复制到显卡的显存中,显存中存储的是字符的ASCII码。

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

显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。从而将显式的信息打印在屏幕上。

8.4 getchar的实现分析

Getchar函数体:

1. int getchar(void)

2. {

3. static char buf[BUFSIZ];

4. static char *bb = buf;

5. static int n = 0;

6. if(n == 0)

7. {

8. n = read(0, buf, BUFSIZ);

9. bb = buf;

10. }

11. return(–n >= 0)?(unsigned char) *bb++ : EOF;

12. }

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

getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。getchar
进行封装,大体上读取字符串的第一个字符然后返回

8.5本章小结

IO是一个程序不可或缺的一个部分,而Linux内核通过UNIX
IO接口将所有IO设备抽象为文件,从而进行优雅的IO处理。C标准库函数建立在UNIX
IO库函数之上,Unix IO函数也是基于对设备进行文件的抽象上。

(第8章1分)

结论

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

程序员编写好一个hello.c文件后,就将其交给编译器处理。

  1. cpp对其进行预处理,进行宏替换等,生成hello.i文件。

  2. ccl对它进行编译,将文本代码编译成汇编代码,汇编代码既具备较好的可读性,又便于转换为机器代码。生成Hello.s文件。

  3. as对它进行汇编,将汇编代码转化为机器代码,生成hello.o文件。

  4. hello.o文件还未包含相应库函数等的定义以及一些必要的系统代码,ld将其与其他必要的.o文件链接在一起,形成一个可执行的、可加载到内存运行的hello.out文件(Linux下)。

  5. 在shell中./hello,shell解析命令行,代表程序员执行了hello程序,创建了hello这个进程,自此,hello程序运行在了PC机上。

  6. 用户可以采用特定的方式给这个进程发送信号——CTRL+C、CTRL+V等,一旦进程被终止,父进程(shell)有义务对其进行回收,防止其称为僵尸进程,占用宝贵的内存资源。

  7. 在hello运行的过程中,涉及到代码与相关数据的加载,这是基于计算机存储体系的:采用Cache技术,很好地兼顾到了容量与速度,做到了二者兼而有之。

  8. 虚拟内存技术实现了对内存的有效管理:在hello进程中,所有信息均存储在虚拟地址空间中,而通过虚拟内存技术,将虚拟地址映射到物理地址。虚拟内存技术也采用了一些十分重要的技术进行优化:TLB——快表作为页表的缓存;多级页表大大减少了页表在内存中的大小,释放了稀缺的内存资源。

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

高度抽象性:信息的表示用二进制抽象;进程是一个最重要、最基本的概念,也是对处理器、IO、存储的高度抽象,有了进程,操作系统的管理就有了对象;虚拟内存对主存以及磁盘的抽象,实现了对内存有效的管理。

不断优化改进:举部分实例说明。虚拟内存已经是对内存管理的一个优化,在基于快表实现的基础上,发觉对快表的访问频繁而且开销大,因此有了TLB技术优化;页表是每个进程独有的,且占用稀缺的内存空间,因此有了多级页表优化;存储大的设备访问慢,反之,基于此,提出了Cache技术,计算机系统的设计是在不断地优化中发展起来的。其次,先有了设计,才能进一步有底层实现,从而针对底层实现进一步优化。

注重效率:系统级的设计是上层应用程序运行的基础。也正基于此,系统设计也就格外注重效率,对系统设计的每一个优化都是格外重要的,哪怕是一个小优化反应至上层应用也可能带来十分可观的效率提升。

严谨性:还是基于系统底层的特征,任何底层的错误都是致命的,对上层应用来说是不可接受的,因此计算机系统的设计显得格外严谨,针对各类异常错误都有相应的处理机制。

设计理念:基于这些特点,对计算机系统进行优化十分有必要,且一定要严密,较应用级程序严谨。

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

附件

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

Hello.c:c源文件

Hello.i:预处理后.i文件

Hello.s:汇编文件

Hello.o:可重定位目标文件

Hello.out:可执行文件(Linux下)

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

参考文献

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

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

  1. 深入理解计算机系统(原书第三版) Randal E. Bryant, David R.
    O’Hallaron著,龚奕利,贺莲 译。

  2. https://www.cnblogs.com/pianist/p/3315801.html
    用Cache技术,很好地兼顾到了容量与速度,做到了二者兼而有之。

  3. 虚拟内存技术实现了对内存的有效管理:在hello进程中,所有信息均存储在虚拟地址空间中,而通过虚拟内存技术,将虚拟地址映射到物理地址。虚拟内存技术也采用了一些十分重要的技术进行优化:TLB——快表作为页表的缓存;多级页表大大减少了页表在内存中的大小,释放了稀缺的内存资源。

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

高度抽象性:信息的表示用二进制抽象;进程是一个最重要、最基本的概念,也是对处理器、IO、存储的高度抽象,有了进程,操作系统的管理就有了对象;虚拟内存对主存以及磁盘的抽象,实现了对内存有效的管理。

不断优化改进:举部分实例说明。虚拟内存已经是对内存管理的一个优化,在基于快表实现的基础上,发觉对快表的访问频繁而且开销大,因此有了TLB技术优化;页表是每个进程独有的,且占用稀缺的内存空间,因此有了多级页表优化;存储大的设备访问慢,反之,基于此,提出了Cache技术,计算机系统的设计是在不断地优化中发展起来的。其次,先有了设计,才能进一步有底层实现,从而针对底层实现进一步优化。

注重效率:系统级的设计是上层应用程序运行的基础。也正基于此,系统设计也就格外注重效率,对系统设计的每一个优化都是格外重要的,哪怕是一个小优化反应至上层应用也可能带来十分可观的效率提升。

严谨性:还是基于系统底层的特征,任何底层的错误都是致命的,对上层应用来说是不可接受的,因此计算机系统的设计显得格外严谨,针对各类异常错误都有相应的处理机制。

设计理念:基于这些特点,对计算机系统进行优化十分有必要,且一定要严密,较应用级程序严谨。

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

附件

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

Hello.c:c源文件

Hello.i:预处理后.i文件

Hello.s:汇编文件

Hello.o:可重定位目标文件

Hello.out:可执行文件(Linux下)

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

参考文献

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

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

  1. 深入理解计算机系统(原书第三版) Randal E. Bryant, David R.
    O’Hallaron著,龚奕利,贺莲 译。

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

附图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
大学生参加学科竞赛有着诸多好处,不仅有助于个人综合素质的提升,还能为未来职业发展奠定良好基础。以下是一些分析: 首先,学科竞赛是提高专业知识和技能水平的有效途径。通过参与竞赛,学生不仅能够深入学习相关专业知识,还能够接触到最新的科研成果和技术发展趋势。这有助于拓展学生的学科视野,使其对专业领域有更深刻的理解。在竞赛过程中,学生通常需要解决实际问题,这锻炼了他们独立思考和解决问题的能力。 其次,学科竞赛培养了学生的团队合作精神。许多竞赛项目需要团队协作来完成,这促使学生学会有效地与他人合作、协调分工。在团队合作中,学生们能够学到如何有效沟通、共同制定目标和分工合作,这对于日后进入职场具有重要意义。 此外,学科竞赛是提高学生综合能力的一种途径。竞赛项目通常会涉及到理论知识、实际操作和创新思维等多个方面,要求参赛者具备全面的素质。在竞赛过程中,学生不仅需要展现自己的专业知识,还需要具备创新意识和解决问题的能力。这种全面的综合能力培养对于未来从事各类职业都具有积极作用。 此外,学科竞赛可以为学生提供展示自我、树立信心的机会。通过比赛的舞台,学生有机会展现自己在专业领域的优势,得到他人的认可和赞誉。这对于培养学生的自信心和自我价值感非常重要,有助于他们更加积极主动地投入学习和未来的职业生涯。 最后,学科竞赛对于个人职业发展具有积极的助推作用。在竞赛中脱颖而出的学生通常能够引起企业、研究机构等用人单位的关注。获得竞赛奖项不仅可以作为个人履历的亮点,还可以为进入理想的工作岗位提供有力的支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值