哈工大计算机系统大作业

2023-11-15

哈工大计算机系统大作业

摘要

本文主要阐述在Linux系统下hello程序的生命周期,了解hello程序从hello.c经过预处理、编译、汇编、链接生成可执行文件的全过程。结合课本的知识详细阐述计算机系统是如何对hello进行进程管理、存储管理和I/O管理,通过对hello生命周期的探索,让我们对计算机系统有更深入的了解。

关键词:hello程序;预处理;编译;汇编;链接;进程管理;存储管理;I/O管理;计算机系统。

第1章 概述

1.1 Hello简介

根据Hello的自白,利用计算机系统的术语,简述Hello的P2P,020的整个过程。
P2P:即为program to process,从程序到进程。在Linux下,程序hello.c在经过cpp的预处理、ccl的编译、as的汇编、ld的链接后最终成为可执行目标程序hello,在shell中键入启动命令后,shell为其fork产生一个子进程,然后hello便从程序变为了进程。
020: shell为此子进程execve,将其映射到虚拟内存,进入程序入口后程序开始载入物理内存,然后进入 main函数执行目标代码,CPU为运行的hello分配时间片执行逻辑控制流。在程序运行结束后,shell父进程负责回收hello进程,内核删除相关数据结构。

1.2 环境与工具

硬件环境:X64 CPU;2GHz;2G RAM;256GHD Disk 以上
软件环境:Windows7 64位以上;VirtualBox/Vmware 11以上;Ubuntu 16.04 LTS 64位/优麒麟 64位
开发与调试工具:gcc,vim,edb,readelf,HexEdit等

1.3 中间结果

名称 作用
hello.i hello.c预处理得到的文件
hello.s hello.i编译得到的汇编文件
hello.o hello.s汇编后得到的可重定位文件
hello 链接后的可执行文件
hello.out hello反汇编后的可重定位文件

1.4 本章小结

本章介绍了hello程序的P2P和020,列出了实验环境和工具以及过程文件等。

第2章 预处理

2.1 预处理的概念与作用

概念:预处理器cpp根据#开头的宏定义、条件编译等命令,修改原始c程序,将引用的库展开合并成一个完整的文本文件。
作用:
1.处理条件编译指令,将#ifdef、#else等指令进行处理,把某部分代码包含进来或排除在外,将不必要的代码过滤掉。
2.处理#define、#include等指令,把相应的定义和对应的头文件加入进来,使得编译程序对其处理。
3.处理一些特殊符号例如LINE、FILE等,用合适的值对其进行替换。

2.2在Ubuntu下预处理的命令

指令:gcc hello.c -E -o hello.i
在这里插入图片描述

2.3 Hello的预处理结果解析

在这里插入图片描述

经过预处理把hello.c文件转换为hello.i文件,可以看到,文件内容相比之前增加许多,但仍然可以找到原来的hello.c文件的内容,且在此基础之上还增加了许多其他文本内容,对源文件中的宏进行展开,加入头文件的内容,如声明函数、定义变量、定义结构体等。还会对相应#define变量进行替换。

2.4 本章小结

本章介绍了预处理的概念和作用,以及经过预处理后程序hello.c发生的变化。

第3章 编译

3.1 编译的概念与作用

编译器把hello.i文件翻译为汇编语言的hello.s文件。以高级程序设计语言书写的源程序作为输入,经过编译后,把以汇编语言表示的目标程序作为输出。

3.2 在Ubuntu下编译的命令

gcc -S hello.i -o hello.s
在这里插入图片描述

3.3 Hello的编译结果解析

在这里插入图片描述
.file:声明源文件
.text:代码节
.section:
.rodata:只读代码段
.align:数据或者指令的地址对其方式
.string:声明一个字符串(.LC0,.LC1)
.global:声明全局变量(main)
.type:声明一个符号是数据类型还是函数类型
3.3.1数据
1.字符串
在这里插入图片描述
上图中可看到程序内的两个字符串在只读数据段中。

leaq .LC0(%rip), %rdi
leaq .LC1(%rip), %rdi
这两个字符串作为printf函数的参数。
2.局部变量
在这里插入图片描述
main函数声明了局部变量i,存放在-4(%rbp)的位置。
3.main函数
参数argc作为传给main的参数,也被放到堆栈中。
在这里插入图片描述
4.立即数
立即数直接体现在代码中。
5.数组
文件中唯一的数组是main函数的第二个参数char *argv[]。
在这里插入图片描述
数组的初始地址存放在-32(%rbp)。
3.3.2函数
1.函数调用与参数传递
在这里插入图片描述
调用该函数前将rdi设置为rax的值进行参数传递,然后call atoi@PLT进行函数调用。
2.函数返回
在这里插入图片描述
通过指令ret进行返回。
3.3.3赋值操作
赋值操作有i=0,主要有mov指令来实现。
在这里插入图片描述
movb:一个字节
movw:两个字节
movl:四个字节
movq:八个字节
3.3.4算数操作
程序中算数操作有i++,由addl实现。还有其他操作。
在这里插入图片描述
在这里插入图片描述
3.3.5关系操作与控制转移
(1)argc!=4
对应编译指令为cmpl $4,-20(%rbp),同时设置条件码决定分支,进行控制转移。
在这里插入图片描述
(2)i<8
在这里插入图片描述
对应编译指令为cmpl $7,-4(%rbp),同时设置条件码决定分支,进行控制转移。
3.3.6类型转换
hello.c中涉及的类型转换是:atoi(argv[3]),将字符串类型转换为整数类型。其他的类型转换还有int、float、double、short、char之间的转换
在这里插入图片描述

3.4 本章小结

本章主要讲述了编译器的作用以及如何处理各种数据和操作,还有c语言各种操作对应的汇编代码。

第4章 汇编

4.1 汇编的概念与作用

汇编器(as)将汇编程序翻译成机器语言指令,把这些指令打包成可重定位目标程序的格式,并将结果保存在.o 目标文件中,.o 文件是一个二进制文件,它包含程序的指令编码。

4.2 在Ubuntu下汇编的命令

gcc hello.s -c -o hello.o
在这里插入图片描述

4.3 可重定位目标elf格式

(1) ELF Header:
命令:readelf -h hello.o
ELF Header:以序列 Magic 开始,描述生成该文件的系统的字的大小和字节顺序,剩下的部分包含帮助链接器语法分析和解释目标文件的信息,其中包括了 ELF 头的大小、目标文件的类型、机器类型、 字节头部表的文件偏移,以及节头部表中条目的大小和数量等信息。
根据头文件的信息,可以看出该文件是可重定位目标文件,有14个节。
在这里插入图片描述
(2)Section Headers
命令:readelf -S hello.o
Section Headers:包含文件中各个节的语义,包括节的类型、位置、大小等,每个节都从零开始因为是可重定位目标文件,根据节头表中的字节偏移信息可知各节的起始位置以及所占空间的大小。还可以看到代码段可执行不能写,数据段和只读数据段不可执行。
在这里插入图片描述
(3).symtab
命令:readelf -s hello.o
.symtab:存放定义和引用的函数和全局变量的信息,name为名称,对应可重定位目标模块;value为起始位置偏移;size为目标大小;Bind表示是本地的还是全局的;type表示类型,要么是函数要么是数据。
在这里插入图片描述
(4)重定位节.real.text
命令:readelf -r hello.o
.real.text:.text 节中位置的列表,包含需要进行重定位的信息,当链接器把这个目标文件和其他文件组合时,需要对这些位置进行修改。
Offset:需要被修改的引用节的偏移
Info:包括symbol和type两部分,symbol在前面三个字节,type在后面三个字节,
symbol:标识被修改的引用应该指向的目标
type:重定位的类型
Type:告知链接器应该如何修改新的应用
Attend:一个有符号常数,一些重定位要使用它对被修改引用的值做偏移调整
Name:重定向到的目标的名称。
在这里插入图片描述

4.4 Hello.o的结果解析

objdump -d -r hello.o 分析hello.o的反汇编,并请与第3章的 hello.s进行对照分析。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
将反汇编代码和hello.s比较可看出,汇编语言的指令并没有不同,反汇编代码不仅显示汇编代码,还有机器代码。机器代码是纯粹的二进制语言,由操作码和操作数构成,是电脑可以真正识别的语言;汇编语言是人们熟悉的语句表述cpu动作形成的语言。每条汇编语言都可以由机器语言表示,建立一一映射关系。可以把汇编语言转换成机器语言看出不同的地方。
(1)条件转移
反汇编指令用确定的地址,hello.s用段符号如L1。
(2)函数调用
.s文件中函数调用直接接函数名称,反汇编文件中call后是下一条指令。

4.5 本章小结

本章对hello.s进行了汇编,生成了hello.o可重定位目标文件,并且分析了可重定位文件的ELF头、节头部表、符号表和可重定位节,比较了hello.s和hello.o反汇编代码的不同之处,分析了从汇编语言到机器语言的一一映射关系。

第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
在这里插入图片描述

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

(1)ELF Header:类型变为EXEC可执行文件,有27个节。
在这里插入图片描述
(2)节头部表Section Headers:对Hello中所有节的信息进行了声明,包括大小size和偏移量offset,根据里面的信息可以定位各个节所占的区间,地址为被加载到虚拟地址的初始地址。
在这里插入图片描述
在这里插入图片描述
(3)重定位节:
在这里插入图片描述
(4)符号表.symtab:
在这里插入图片描述
在这里插入图片描述

5.4 hello的虚拟地址空间

查看edb得出,hello虚拟地址起始于0x400000, 结束于0x400ff0。
在这里插入图片描述
在这里插入图片描述
根据前面的节头部表,可以通过edb查看各个节的信息。比如.text节,虚拟地址开始于0x4010f0,大小为0x145.
在这里插入图片描述

5.5 链接的重定位过程分析

经过对hello和hello.o的比较分析,可以看出hello反汇编的代码有明确的虚拟地址,即完成了重定位,而hello.o中虚拟地址为0,未完成重定位,如下图所示。
在这里插入图片描述
在这里插入图片描述
除此之外,hello反汇编代码中多出了其他节和额外的汇编代码。如下图。
在这里插入图片描述

5.6 hello的执行流程

ld-2.27.so!_dl_start—
ld-2.27.so!_dl_init—
hello!_start—
hello!_init—
hello!main—
hello!puts@plt–
hello!exit@plt–
hello!printf@plt–
hello!sleep@plt–
hello!getchar@plt–
sleep@plt—

5.7 Hello的动态链接分析

共享链接库代码是动态的目标模块,在程序开始运行或者调用程序加载时,可以自动加载该代码到任意的一个内存地址,并和一个在目标模块内存中的应用程序链接起来,这个过程就是对动态链接的重定位过程。
动态的链接器在正常工作时采取了延迟绑定的链接器策略,由于静态的编译器本身无法准确预测变量和函数的绝对运行时地址,动态的链接器需要等待编译器在程序开始加载时再对编译器进行延迟解析,这样的延迟绑定策略称之为动态延迟绑定。在plt和got中分别存放着链接器的目标变量和函数的运行时地址。一个动态的链接器通过静态的过程偏移链接表plt+got链接器实现函数的动态过程链接,这样一来,它就已经包含了正确的绝对运行时地址。

5.8 本章小结

本章介绍了链接的概念和作用,阐述hello.o如何链接成为可执行文件,介绍了ELF格式和各个节的含义。

第6章 hello进程管理

6.1 进程的概念与作用

进程是执行中程序的实例,有其自己的地址空间,进程为客户提供了一种假象:
(1)我们的进程是系统中当前唯一运行的程序,独占处理器和内存。
(2)处理器无间断地执行进程。

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

Linux系统中shell是交互型应用级程序,代表用户运行其他程序。
其基本功能是解释并运行用户的指令,重复如下处理过程:
(1)终端进程读取用户通过键盘输入的命令行。
(2)分析命令行字符串,获取命令行参数,并构造传递给execve的argv向量
(3)检查第一个命令行参数是否是一个内置的shell命令
(4)如果不是内部命令,调用fork( )创建子进程
(5)在子进程中,用步骤2获取的参数,调用execve( )执行指定程序。
(6)如果用户没要求后台运行(命令末尾没有&号)则shell使用waitpid(或wait…)等待作业终止后返回。
(7)如果用户要求后台运行(如果命令末尾有&号),则shell返回;

6.3 Hello的fork进程创建过程

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

以我们的hello为例,当我们输入 ./hello 1190201403 张偲博 1 的时候,首先shell对我们输入的命令进行解析,由于我们输入的命令不是一个内置的shell命令,因此shell会调用fork()创建一个子进程。

6.4 Hello的execve过程

在创建了一个子进程后,子程序调用execve函数在上下文加载hello程序。
(1)删除当前虚拟地址中已存在的用户区域。
(2)为新程序建立新的区域结构,这些区域结构是私有的,虚拟地址空间的代码和数据区域被映射为hello文件的.txt和.data区,bss区域是请求二进制零的,映射匿名文件,其大小包含在hello文件中。栈和堆区域也是请求二进制零的,初始长度为零。
(3)如果hello与共享对象链接,那么这些对象都被动态链接到这个程序,然后映射到用户虚拟地址空间中的共享区域。
(4)设置程序计数器,使之指向代码区域的入口点,下次调用这个进程时,从这个入口点开始执行。
在这里插入图片描述

6.5 Hello的进程执行

在调用进程发送sleep之前,hello在当前的用户内核模式下运行,在内核中进程再次调用当前的sleep之后进程转入用户内核等待休眠模式,内核中所有正在处理等待休眠请求的应用程序主动请求释放当前正在发送处理sleep休眠请求的进程,自动将当前调用hello的进程加入正在执行等待的队列,移除或退出正在内核中执行的进程等待队列。
设置定时器,休眠的时间为自己设置的时间,当计时器时间到,发送一个中断信号。内核收到中断信号进行中断处理,hello被重新加入运行队列,等待执行,这时候hello就可以运行在自己的逻辑控制流里面了。
在这里插入图片描述

6.6 hello的异常与信号处理

hello执行过程中会出现哪几类异常,会产生哪些信号,又怎么处理的。
程序运行过程中可以按键盘,如不停乱按,包括回车,Ctrl-Z,Ctrl-C等,Ctrl-z后可以运行ps jobs pstree fg kill 等命令,请分别给出各命令及运行结截屏,说明异常与信号的处理。
异常分为四类:中断、陷阱、故障、终止
在这里插入图片描述
常见信号:
在这里插入图片描述
正常执行:
在这里插入图片描述
按下ctrl+z将进程挂起,hello进程没有回收,而是运行在后台,使用ps命令可以看到。调用fg 1将其调到前台,首先打印命令行命令,然后把剩余info输出。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
按下ctrl+c会导致内核发送SIGINT信号到前台进程组的每个进程,默认情况是终止前台作业,用ps查看前台进程组没有hello进程。
在这里插入图片描述
在这里插入图片描述
程序运行时乱按键盘,会发现屏幕的输入缓存到stdin。getchar的时候读出一个’\n’结尾的字符串,其他当作命令行输入。
在这里插入图片描述

6.7本章小结

本章阐述了进程的概念和作用,介绍了shell的处理流程,分析了fork创建进程和调用execve函数的流程,hello的进程执行和异常处理。

第7章 hello的存储管理

7.1 hello的存储器地址空间

结合hello说明逻辑地址、线性地址、虚拟地址、物理地址的概念。
逻辑地址:程序编译后出现在汇编代码中的地址,用来指定一个操作数或一条指令的地址,由段标识符加上偏移量表示。
线性地址:一个逻辑地址经过段地址机制转化后变成一个线性分页地址,线性地址可以再经过物理地址变换以产生一个新的物理分页地址。线性地址是逻辑地址和物理地址变换的中间层。
虚拟地址:即线性地址
物理地址:用于内存芯片级的单元寻址,与处理器和CPU链接的地址总线相对应。可以直接把物理地址理解成插在机器上的内存本身,把内存看成一个从0字节一直到最大空量逐字节编号的大数组,把这个数组叫做物理地址

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

首先,给定一个完整的逻辑地址[段选择符:段内偏移地址],
1.看段选择符的T1=0还是1,判断当前要转换是GDT中的段还是LDT中的段,再根据相应寄存器,得到其地址和大小。我们就有了一个数组。
2.拿出段选择符中前13位,可以在这个数组中,查找到对应的段描述符,这样基地址就知道了。
3.把Base + offset,就是要转换的线性地址了。

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

在分页的机制下地址转化管理机制主要实现了虚拟地址向虚拟地址物理页或内存地址的非线性分页转化。vm内存系统将虚拟内存的块大小分割成作为一个被我们称为基于虚拟页的内存大小固定的块用来进行处理这个固定大小的内存问题,每个称为虚拟页的内存大小可以固定为2^p个单位字节。类似的,物理块和虚拟内存被再一次细分为一个物理页,大小与每一个虚拟页的地址大小与其对应的值相等。例如:一个32位的虚拟机器,线性的地址可以最大达到4gb,用4kb为一个页来进行划分,也可以分为1m个页,通过页表处理和查找这些虚拟页的数据,方便对线性地址的大小进行管理。
之后计算机会进行一个翻译操作,把一个n元素的虚拟地址空间中的虚拟元素与一个m元素的另一个物理虚拟地址空间相互进行映射,这个翻译操作被我们称为地址翻译。
地址翻译示意图如下
在这里插入图片描述
虚拟地址由对应的虚拟物理页号和虚拟页偏移量共同组成,类似的,物理地址由虚拟物理页偏移号和对应的物理页偏移量共同分配组成。页表中物理地址存在三种常见的情况:未分配:没有在虚拟内存的空间中分配该条目的内存;未分配缓存:在虚拟内存的空间中已经分配了但是没有被直接缓存到对应物理地址的内存中;已分配已缓存:内存已经缓存在了对应物理地址的内存中。页表的基址寄存器在页表中可以获得条目,通过对比条目对应的有效位判断物理地址是上述哪一种的情况,如果有效则通过提取得出对应物理地址的页号寄存器,与对应的虚拟页偏移量共同分配构成了物理地址寄存器pa。
在这里插入图片描述
当页面命中时CPU硬件执行的步骤:
第1步:处理器产生一个虚拟地址,将它传送给地址管理单元MMU。
第2步: MMU生成PTE地址,并从高速缓存/主存请求得到它。
第3步:高速缓存或者主存向MMU返回PTE。
第4步:MMU构造物理地址,并把它传送给高速缓存/主存。
第5步:高速缓存或者主存会返回所请求的数据字给处理器。

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

按照上述模式,每次CPU产生一个虚拟地址并且发送给地址管理单元,MMU必须找到一个PTE用来将虚拟地址翻译为物理地址。为了消除这种操作带来的大量时间开销,MMU中被设计了一个关于PTE的小的缓存,称为翻译后备缓冲器。例如当每次cpu发现需要重新翻译一个虚拟地址时,它就必须发送一个vpn得到虚拟地址mmu,发送一个vpo位得到一个l1高速缓存.
corei7采用四级页表层次结构,每个四级页表进程都有自己私有的页表层次结构,这种设计方法从两个基本方面减少了对内存的需求,如果一级页表的pte全部为空,那么二级页表就不会继续存在,从而为进程节省了大量的内存,而且也只有一级页表才会有需要总是在一个内存中。四级页表的层次结构操作流程如下:36位虚拟地址被寄存器划分出来组成四个9位的片,每个片被寄存器用作到一个页表的偏移量。cr3寄存器内储存了一个l1页表的一个物理起始基地址,指向第一级页表的一个起始和最终位置,这个地址是页表上下文的一部分信息。vpn1提供了到一个l1pet的偏移量,这个pte寄存器包含一个l2页表的起始基地址.vpn2提供了到一个l2pte的偏移量,一共四级,逐级以此层次类推。
在这里插入图片描述

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

L1Cashe的物理访存大致过程如下:
(1) 组选择:取出虚拟地址的组索引位,把二进制组索引转化为一个无符号整数,找到相应的组
(2) 行匹配:把虚拟地址的标记为拿去和相应的组中所有行的标记位进行比较,当虚拟地址的标记位和高速缓存行的标记位匹配时,而且高速缓存行的有效位是1,则高速缓存命中。
(3) 字选择:一旦高速缓存命中,我们就知道我们要找的字节在这个块的某个地方。因此块偏移位提供了第一个字节的偏移。把这个字节的内容取出返回给CPU。
(4)不命中:如果高速缓存不命中,那么需要从存储层次结构中的下一层取出被请求的块,然后将新的块存储在组索引位所指示的组中的一个高速缓存行中。一种简单的放置策略如下:如果映射到的组内有空闲块,则直接放置,产生冲突,则采用最近最少使用策略 LFU进行替换。
在这里插入图片描述
Cashe2,Cashe3原理相同。

7.6 hello进程fork时的内存映射

shell调用fork时,内核为新进程创建各种数据结构并分配唯一的PID,为了给这个新进程创建虚拟内存,它创建了当前进程的 mm_struct、区域结构和页表的原样副本。它将两个进程的两个页面都标记为只读,并将两个进程中的每个区域结构都标记为私有的写时复制。

7.7 hello进程execve时的内存映射

在创建了一个子进程后,子程序调用execve函数在上下文加载hello程序。
(1)删除当前虚拟地址中已存在的用户区域。
(2)为新程序建立新的区域结构,这些区域结构是私有的,虚拟地址空间的代码和数据区域被映射为hello文件的.txt和.data区,bss区域是请求二进制零的,映射匿名文件,其大小包含在hello文件中。栈和堆区域也是请求二进制零的,初始长度为零。
(3)如果hello与共享对象链接,那么这些对象都被动态链接到这个程序,然后映射到用户虚拟地址空间中的共享区域。
(4)设置程序计数器,使之指向代码区域的入口点,下次调用这个进程时,从这个入口点开始执行。
在这里插入图片描述

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

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

7.9动态存储分配管理

Printf会调用malloc,请简述动态内存管理的基本方法与策略。
动态内存分配器维护者一个进程的虚拟内存区域,称为堆。分配器将堆视为一组不同的大小的块的集合来维护。每个块就是一个连续的虚拟内存片,要么是已分配的,要么是空闲的。分配器有两种基本风格。两种风格都是要求显示的释放分配块。
(1) 显式分配器:要求应用显示的释放任何已分配的块。例如C标准库提供一个叫做malloc程序包的显示分配器。
(2) 隐式分配器:要求分配器检测一个已分配块何时不再被程序使用,那么就释放这个块。隐式分配器也叫垃圾收集器。
1.隐式空闲链表
在这里插入图片描述
这种情况下,一个块是由一个字的头部、有效载荷,以及可能的填充组成。头部编码了这个块的大小以及这个块是已分配的还是空闲的。块的头最后一位指明这个块是已分配的还是空闲的。

头部后面是应用malloc时请求的有效载荷。有效载荷后面是一片不使用的填充块,其大小任意。空闲块通过头部块的大小字段隐含的连接着,所以我们称这种结构为隐式空闲链表。
在这里插入图片描述
2.显示空闲链表
显示空闲链表是将空闲块组织为某种形式的显示数据结构。堆被组织为双向空闲链表,在每个空闲块中,都包含一个前驱和后继的指针。
在这里插入图片描述
使用双向链表而不是隐式空闲链表,使首次适配的分配时间从块总数的线性时间减少到了空闲块数量的线性时间。
一种方法使用后进先出的顺序维护链表,将新释放的块在链表的开始处。使用LIFO的顺序和首次适配的放置策略,分配器会最先检查最近使用过的块,在这种情况下,释放一个块可以在线性的时间内完成,如果使用了边界标记,那么合并可以在常数时间内完成。
按照地址顺序来维护链表,其中链表中的每个块的地址都小于它的后继的地址,在这种情况下,释放一个块需要线性时间的搜索来定位合适的前驱。平衡点在于,按照地址排序首次适配有着更高的内存利用率,接近最佳适配的利用率。

7.10本章小结

本章对hello程序运行时虚拟地址的变化进行分析,解析了hello应用程序的虚拟存储地址空间,分析了虚拟地址,线性地址和虚拟物理线性地址之间的互相转换,页表的命中与不页表的命中,使用动态快表缓存作为页表的高速缓存以及如何加速页表,动态内存管理的操作,fork时的动态内存中断与映射、execve时的动态内存中断与映射、缺页的中断与缺页映射和中断的处理。

第8章 hello的IO管理

8.1 Linux的IO设备管理方法

设备的模型化:文件
设备管理:unix io接口
一个Linux文件就是一个m字节的序列。
所有的I/O设备都可以被模型化为文件,相应的输入输出就是对文件的读和写,这种方式允许Linux内核引出简单低级的应用接口即unix io接口

8.2 简述Unix IO接口及其函数

接口:
(1)打开文件。一个应用程序通过要求内核打开相应的文件,来访问一个 I/O 设备,内核返回一个小的非负整数作为描述符,它在后续对此文件的所有操作中标识这个文件,内核记录有关这个打开文件的所有信息。
(2)Shell 创建的每个进程都有三个打开的文件:标准输入,标准输出,标准错误。 (3)改变当前的文件位置:对于每个打开的文件,内核保持着一个文件位置 k,初始为 0,这个文件位置是从文件开头起始的字节偏移量。
(4)读写文件:一个读操作就是从文件复制 n>0 个字节到内存,从当前文件位置 k 开始,然后将 k 增加到 k+n,给定一个大小为 m 字节的而文件,当 k>=m 时,触发 EOF。类似一个写操作就是从内存中复制 n>0 个字节到一个文件,从当前文件位置k开始,然后更新k。
(5)关闭文件,内核释放打开文件时创建的数据结构,并将这个描述符恢复到可用的描述符池中去。
函数:
(1)int open(char* filename,int flags,mode_t mode) ,进程通过调用 open 函数来打开一个存在的文件或是创建一个新文件。
(2)int close(fd),fd 是需要关闭的文件的描述符,close 返回操作结果。

8.3 printf的实现分析

https://www.cnblogs.com/pianist/p/3315801.html
从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall等.
字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。
显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。
printf函数体:
static int printf(const char *fmt, …)
{
va_list args;
int i;

 va_start(args, fmt);
 write(1,printbuf,i=vsprintf(printbuf, fmt, args));
 va_end(args);
 return i;
}

该程序按照fmt格式结合参数args生成字符串,并返回长度。
write函数:
write:
mov eax, _NR_write
mov ebx, [esp + 4]
mov ecx, [esp + 8]
int INT_VECTOR_SYS_CALL
在printf中调用系统函数write(buf,i)将长度为i的buf输出,在write函数中,将栈中参数放入寄存器,ecx是字符个数,ebx存放第一个字符地址,
int INT_VECTOR_SYS_CALLA代表通过系统调用syscall。
syscall函数:
sys_call:
call save

 push dword [p_proc_ready]

 sti

 push ecx
 push ebx
 call [sys_call_table + eax * 4]
 add esp, 4 * 3

 mov [esi + EAXREG - P_STACKBASE], eax

 cli

 ret

syscall将字符串中的字节从寄存器中复制到显卡的显存中,显存中存储的是字符的ASCII码。字符显示驱动子程序通过ASCII码在字模库中找到点阵信息将点阵信息存储到vram中。显示芯片按照一定的刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点。于是我们的打印字符串就显示在了屏幕上。

8.4 getchar的实现分析

异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。
getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。大概思想是读取字符串的第一个字符后返回。

8.5本章小结

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

结论

用计算机系统的语言,逐条总结hello所经历的过程。
你对计算机系统的设计与实现的深切感悟,你的创新理念,如新的设计与实现方法。
首先,从文本编辑器开始我们写出hello.c文件,也是我们之前最为熟悉的一种。之后我们往往直接在软件上将其编译链接,得出程序运行的结果,但其实这个过程中还包括了许多步骤。
先要对其进行预处理,把各种库加入进来,把一些宏定义进行处理,产生hello.i,到此处才只是一个开始,接下来通过编译,hello.i又变为了hello.s文件,里面是用汇编语言书写的,经过学习我们也可以大致看懂里面的内容,和我们在c文件里的大致相近,实现的目的相同,但往往也可以看到一些不同,我们可以据此对程序进行优化。
随后要把hello.s变为我们的计算机真正看得懂的可重定位文件hello.o,通过动态链接最终得到可执行文件hello,到此为止完成了P2P。
随后我们在shell上输入命令行,shell读取我们的命令,调用fork和execve为我们的hello加载虚拟内存,分配时间片,在此期间程序通过我们的缓存结构,从内存或cache、磁盘等位置取得数据。
ctrl+z可以将其挂起,ctrl+c可以将其终止。最后,shell将其回收,删除创立的数据结构,至此hello结束了它的一生。
计算机系统这门课让我对于计算机有了系统的了解,也让我感受到了计算机的魅力,环环相扣严丝合缝,追求效率的同时也要保持正确性,希望以后可以对于计算机有更深刻的认知。

附件

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

名称 作用
hello.i hello.c预处理得到的文件
hello.s hello.i编译得到的汇编文件
hello.o hello.s汇编后得到的可重定位文件
hello 链接后的可执行文件
hello.out hello反汇编后的可重定位文件

参考文献

为完成本次大作业你翻阅的书籍与网站等
[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.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

哈工大计算机系统大作业 的相关文章

  • 汇编语言+IDA安装问题解决汇总

    利用汇编语言计算机和人类链接更为便捷如下图所示 寄存器 简单讲就是CPU可以存储数据的器件 一个CPU可以有多个寄存器 AX BX是两个不同的寄存器 16位处理器有14个寄存器 AX BX CX DX SI DI SP BP IP CS S
  • linux 文件十六进制阅读_Linux引导101

    对于Ubuntu 18 04 gt Photo by Adi Goldstein on Unsplash 让我们从Wikipedia如何描述引导程序开始 通常 自举通常是指自启动过程 应该在没有外部输入的情况下进行 在计算机技术中 该术语
  • jquery中ajax处理跨域的三大方式

    由于JS同源策略的影响 因此js只能访问同域名下的文档 因此要实现跨域 一般有以下几个方法 一 处理跨域的方式 1 代理 2 XHR2 HTML5中提供的XMLHTTPREQUEST Level2 及XHR2 已经实现了跨域访问 但ie10
  • Oracle 11g数据库安装之后没有OracleOraDb11g_home1TNSListener服务

    1 在安装目录下F Oracle Server product 11 2 0 dbhome 1 BIN netca deinst bat 以管理员身份运行 会出现命令窗口 执行完会自己退出 2 再以管理员身份启动netca bat 重新配置
  • 快速乘和改造快速幂

    快速乘和改造快速幂 文章目录 快速乘和改造快速幂 快速乘 快速幂改造 典型例题 参考材料 快速乘 因为我们知道乘法有时候会溢出 即使是long也可能因为结果过大而溢出 当模数也是long类型时 所以我们需要寻找一种能高效完成乘法操作并且不会
  • AntDB数据库参加ACDU中国行杭州站,分享数据库运维实践与经验

    关于ACDU 和中国行 ACDU是由墨天轮社区举办的中国数据库联盟的品牌活动之一 在线下汇集数据库领域的行业知名人士 共同探讨数据库前沿技术及其应用 促进行业发展和创新的平台 也为开发者们提供友好交流的机会 AntDB作为具有技术前瞻性的国
  • 转:SpringMVC 返回 json 字符串中文乱码

    版权声明 本文为博主原创文章 遵循 CC 4 0 BY SA 版权协议 转载请附上原文出处链接和本声明 本文链接 https blog csdn net wenteryan article details 79803691 原因 最近在写一
  • terminate called after throwing an instance of 'std::out_of_range' what(): basic_string::substr

    运行时报错 terminate called after throwing an instance of std out of range what basic string substr pos Aborted core dumped 内
  • 地址 脱敏规则_Java对姓名, 手机号, 身份证号, 地址进行脱敏

    替换几位就用几个 号 一 姓名 1 脱敏规则 只显示第一个汉字 比如李某某置换为李 李某置换为李 private staticString desensitizedName String fullName if Strings isNull
  • android 监听 webkit,androidx.webkit

    androidx webkit Requirements The minimum sdk version to use this library is 14 How to declare the dependencies to use th
  • 如何将Web应用打包成.war文件?

    将Web应用打包成WAR文件的方法 1 在命令行中运用Jar命令 假定有一个Web应用 C myHome myHome WEB INF myHome files myHome image myHome src myHome index js
  • JVM 类加载机制全面解析,一篇完整彻底搞懂

    我是目录 1 概述 2 类的生命周期 3 类加载器 4 类加载机制 双亲委派机制 1 概述 2 类的生命周期 包括7个阶段 加载 验证 准备 解析 初始化 使用 和 卸载 其中验证 准备 解析3个部分统称为连接 Linking 解析阶段 在
  • 第二篇:数据仓库与数据集市建模

    阅读目录 前言 维度建模的基本概念 维度建模的三种模式 实例 零售公司销售主题的维度建模 更多可能的事实属性 经典星座模型 缓慢变化维度问题 数据仓库建模体系之规范化数据仓库 数据仓库建模体系之维度建模数据仓库 数据仓库建模体系之独立数据集
  • linux安装jdk之后,系统默认使用openjdk解决方法

    前两天装了个虚拟机配置java环境变量之后 java version 发现使用的仍然是 openjdk 咨询了下公司里的大神 成功解决 我配置的环境变量 export JAVA HOME home hadoop softwares jdk1
  • 在Windows 10中开启FTP服务

    在Windows 10中开启FTP服务 你需要首先安装FTP服务器功能 然后配置FTP站点 以下是详细步骤 步骤1 安装FTP服务器 打开 控制面板 点击 程序 点击 打开或关闭Windows功能 在弹出的Windows功能列表中 找到并展
  • sudo pip install -i https://pypi.douban.com/simple --user MySQL-python报错‘my_config.h‘ file not found

    异常 Google了无数次 都没用 后面无意之间看到了一篇博客 https www codenong com cs107125972 按照他的方式改了 但是没有用 仔细检查异常报错后 到了client的目录 copy了一个文件之后可以了
  • C-实现写一函数concat,将两个字符串连接(不能使用字符串函数)

    题目描述 写一函数concat 将两个字符串连接 不能使用字符串函数 输入 两行字符串 输出 连接后的字符串 样例输入 123 abc 样例输出 123abc 提示 来源 admin 算法思路 创建三个字符型数组 接受两组输入字符串 和合并
  • 一款超赞的算法可视化工具,让算法过程动态展示出来

    从文字或者图片中学习算法还是一件很无聊的事 当然 现在有许多很棒的网站可以查看各种算法的动画 然而 对于开发人员来说 如果能将实现算法的代码的实际执行操作通过可视化展现出来 那就是最好不过了 推荐一款开源工具 Algorithm Visua
  • 智星算力平台-网页版使用教程

    1 注册登录 网页搜索http gpu ai galaxy cn store 新用户点击右上角快速注册 2 算力市场 登录账号后进入首页 开始选择租用GPU 1 场景选择 根据使用需求选择所需场景 如不知该选云容器还是云主机可参考以下图解
  • Numpy 一维数组的倒序

    代码 方法一 import numpy as np a np array 1 2 3 4 5 6 b a 1 print b 方法二 a np array 1 2 3 4 5 6 b np flipud a print b 输出 D Ana

随机推荐

  • 使用面向对象的方式设计一段python多线程爬虫代码

    可以这样 import threading import requests def spider url response requests get url print response text if name main url list
  • 百望云亮相服贸会 重磅发布业财税融Copilot

    小望小望 我要一杯拿铁 好的 已下单成功 请问要开具发票嘛 在获得确认的指令后 百小望AI智能助手 按用户要求成功开具了一张电子发票 这是2023年服贸会国家会议中心 成果发布现场 百望云向与会嘉宾展示的业财税融Copilot产品的一个应用
  • jedis详细配置

    最大活动对象数 redis pool maxTotal 1000 最大能够保持idel状态的对象数 redis pool maxIdle 100 最小能够保持idel状态的对象数 redis pool minIdle 50 当池内没有返回对
  • Zookeeper概念简介+Zookeeper工作原理图+选主机制+Zookeeper集群角色+数据模型+规则

    Zookeeper是一个分布式协调服务 就是为用户的分布式应用程序提供协调服务 zookeeper是为别的分布式程序服务的 Zookeeper本身就是一个分布式程序 只要有半数以上节点存活 zk就能正常服务 Zookeeper所提供的服务涵
  • 【C++简明教程】随机数生成

    导言 C 简明教程 每次更新将会以代码块的形式发布 可以作为手册或者模块以供查询 今天介绍的是如何使用 C 生成随机数 随机数生成 C 自带的随机数生成函数 rand 但是这个不是实际意义上的随机数生成函数 rand 返回一随机数值的范围在
  • activemq结合mqtt发送p2p消息

    实现思路 所有用户订阅一个主题 当服务器端发起推送时使用jms协议发送消息到主题 并设置附带属性为目标用户的clientId 对该主题进行自定义分发策略 1 下载mqtt源码 自行下载 本案例以5 5 10为例 2 自定义分发策略 添加一个
  • BIO、NIO、AIO的区别

    1 简单介绍 同步阻塞 blocking IO 简称BIO 同步非阻塞 non blocking IO 简称NIO 异步非阻塞 asynchronous non blocking IO 简称AIO BIO 同步阻塞I O模式 数据的读取写入
  • 若依实现父弹窗获取子弹窗的数据

    参考这个 RuoYi 弹出新窗口选择数据回显到父页面 https blog csdn net u014440968 article details 116266076 还有官方的demo就行 最终实现效果 关键的方法 父页面 div cla
  • 基于ESB权限初始化流程开发总结

    在集团信息化系统的建设过程中 由于应用系统数量日益增多 很多集团缺少一个能有效地将众多系统身份认证 账号管理 授权等功能集成的软件系统 由此IDM应运而生 在IDM中统一权限的功能资源模块是对下游系统的平台进行功能资源的统一管控 在管控之前
  • HTTP学习——网关

    网关可以作为一种翻译器使用 抽象出了一种能够到达资源的方法 网关和代理的区别 代理连接的是两个或多个使用相同协议的应用程序 而网关连接的则是两个或多个使用不同协议的端点 网关扮演的是 协议转换器 的角色 Web网关在一侧使用HTTP协议 在
  • 离散数学 --- 命题逻辑 -- 命题符号化与命题公式

    第一部分 命题符号化及其应用 1 等价连接词中 P Q同为真同为假时为真 真假不同时为假 下面是各个联结词的真值表 复合命题的真值只取决于通过联结词构成他的简单命题的真值 与简单命题的内容无关 比如 中国在地球上且太阳东升西落 这是一个复合
  • 记录DHCP IPV6遇到的问题(一)

    进行DHCP IPV6连接的时候 经常遇到设备获取过一次地址后 在短时间内再次重新主动进行一次DHCP IPV6连接 会连接失败 从抓包来分析就是上行服务器不响应 通过与服务器方的沟通 了解到一点 服务器会记录请求设备的mac和DUID 是
  • SpringMVC的架构有什么优势?——视图与模型(二)

    前言 作者主页 雪碧有白泡泡 个人网站 雪碧的个人网站 推荐专栏 java一站式服务 React从入门到精通 前端炫酷代码分享 从0到英雄 vue成神之路 uniapp 从构建到提升 从0到英雄 vue成神之路 解决算法 一个专栏就够了 架
  • 一文拆解Faas的真实案例

    欢迎大家前往腾讯云 社区 获取更多腾讯海量技术实践干货哦 本文来自腾讯云技术沙龙 本次沙龙主题为Serverless架构开发与SCF部署实践 刘敏洁 具有多年云计算行业经验 曾任职于华为 UCloud等企业担任产品开发 产品经理 目前负责腾
  • meedu二次开发:企业内部使用 必须登录之后才能查看里面内容

    meedu二次开发 修改成企业内部培训系统功能 用户必须登录之后才能查看里面课程内容
  • C语言第五章第4节用for语句实现循环学习导案

    课 题 5 4 用for语句实现循环 课时安排 2课时 课 型 新授 学 习目标 掌握for循环语句的一般形式 掌握for循环语句的执行过程 重点 for循环语句的一般形式 难点 理解for循环语句的执行过程并会做题 导 学 流 程 复备或
  • 实习日志3.22

    今天是实习的第一天 主要做了以下工作 1 安装vs2017 在csdn直接下载安装包 官网找不到2017版本的社区版 2 配置opencv编译环境 4 2 0版本 推荐b站up3 3 遇到了bug 找不到opencv core420d dd
  • PyTorch报错insufficient shared memory (shm)

    报错 ERROR Unexpected bus error encountered in worker This might be caused by insufficient shared memory shm ERROR Unexpec
  • 高并发分布式架构演进

    架构演进过程如下 单机架构 第一次演进 Tomcat与数据库分开部署 第二次演进 引入本地缓存和分布式缓存 第三次演进 引入反向代理实现负载均衡 第四次演进 数据库读写分离 第五次演进 数据库按业务分库 第六次演进 把大表拆分为小表 第七次
  • 哈工大计算机系统大作业

    哈工大计算机系统大作业 摘要 本文主要阐述在Linux系统下hello程序的生命周期 了解hello程序从hello c经过预处理 编译 汇编 链接生成可执行文件的全过程 结合课本的知识详细阐述计算机系统是如何对hello进行进程管理 存储