ICS——Hello的一生

计算机科学与技术学院
2021年5月
摘 要
本文就一个简单的hello.c文件,概述了其在系统(Linux)上是如何编译、链接、汇编、生成可执行文件,其可执行文件在执行过程中,其内存分配管理,进程管理,数据代码地址的管理映射,信号的接受与处理等。

关键词:计算机系统;c语言;Linux系统

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

目 录

第1章 概述 - 4 -
1.1 HELLO简介 - 4 -
1.2 环境与工具 - 4 -
1.3 中间结果 - 4 -
1.4 本章小结 - 4 -
第2章 预处理 - 5 -
2.1 预处理的概念与作用 - 5 -
2.2在UBUNTU下预处理的命令 - 5 -
2.3 HELLO的预处理结果解析 - 5 -
2.4 本章小结 - 5 -
第3章 编译 - 6 -
3.1 编译的概念与作用 - 6 -
3.2 在UBUNTU下编译的命令 - 6 -
3.3 HELLO的编译结果解析 - 6 -
3.4 本章小结 - 6 -
第4章 汇编 - 7 -
4.1 汇编的概念与作用 - 7 -
4.2 在UBUNTU下汇编的命令 - 7 -
4.3 可重定位目标ELF格式 - 7 -
4.4 HELLO.O的结果解析 - 7 -
4.5 本章小结 - 7 -
第5章 链接 - 8 -
5.1 链接的概念与作用 - 8 -
5.2 在UBUNTU下链接的命令 - 8 -
5.3 可执行目标文件HELLO的格式 - 8 -
5.4 HELLO的虚拟地址空间 - 8 -
5.5 链接的重定位过程分析 - 8 -
5.6 HELLO的执行流程 - 8 -
5.7 HELLO的动态链接分析 - 8 -
5.8 本章小结 - 9 -
第6章 HELLO进程管理 - 10 -
6.1 进程的概念与作用 - 10 -
6.2 简述壳SHELL-BASH的作用与处理流程 - 10 -
6.3 HELLO的FORK进程创建过程 - 10 -
6.4 HELLO的EXECVE过程 - 10 -
6.5 HELLO的进程执行 - 10 -
6.6 HELLO的异常与信号处理 - 10 -
6.7本章小结 - 10 -
第7章 HELLO的存储管理 - 11 -
7.1 HELLO的存储器地址空间 - 11 -
7.2 INTEL逻辑地址到线性地址的变换-段式管理 - 11 -
7.3 HELLO的线性地址到物理地址的变换-页式管理 - 11 -
7.4 TLB与四级页表支持下的VA到PA的变换 - 11 -
7.5 三级CACHE支持下的物理内存访问 - 11 -
7.6 HELLO进程FORK时的内存映射 - 11 -
7.7 HELLO进程EXECVE时的内存映射 - 11 -
7.8 缺页故障与缺页中断处理 - 11 -
7.9动态存储分配管理 - 11 -
7.10本章小结 - 12 -
第8章 HELLO的IO管理 - 13 -
8.1 LINUX的IO设备管理方法 - 13 -
8.2 简述UNIX IO接口及其函数 - 13 -
8.3 PRINTF的实现分析 - 13 -
8.4 GETCHAR的实现分析 - 13 -
8.5本章小结 - 13 -
结论 - 14 -
附件 - 15 -
参考文献 - 16 -

第1章 概述
1.1 Hello简介
根据Hello的自白,利用计算机系统的术语,简述Hello的P2P,020的整个过程。
P2P:Hello.c是一个用高级语言编写的文本文件;经过cpp预处理,将#include的头文件包含进文件,进行宏替换,并删去注释,生成.i文件;经过ccl编译器处理,生成.s汇编程序,即使用汇编语言的文本文件;再由as汇编器转为二进制可重定位目标程序.o文件;经过ld连接器链接生成最终的可执行文件。当在shell中,输入可执行目标文件时,shell会fork一个新的子进程,并在其中调用execve,执行可执行文件。
020:最开始程序不在内存中,即是“0”的状态。当在shell中加载了可执行文件后,操作系统为之分配了部分虚拟空间,并将其加载其中。最后,程序结束后,shell回收该进程,内核释放该进程的虚拟空间,则相关数据又变成了“0”。
1.2 环境与工具
1.2.1 硬件环境
X64 CPU;2GHz;2G RAM;256GHD Disk 以上
1.2.2 软件环境
Windows7 64位以上;VirtualBox/Vmware 11以上;Ubuntu 16.04 LTS 64位/优麒麟 64位;
1.2.3 开发工具
Visual Studio 2010 64位以上;GDB/OBJDUMP;DDD/EDB等
1.3 中间结果
列出你为编写本论文,生成的中间结果文件的名字,文件的作用等。
Hello.c——c语言代码文件
Hello.i——预编译后的文件
Hello.s——汇编代码文件
Hello.o——可重定位文件
Hello——可执行文件
1.4 本章小结
本小节对hello的P2P和020进行了简单的介绍,列明了实验环境和开发工具,并生成了相应的文件。

(第1章0.5分)

第2章 预处理
2.1 预处理的概念与作用
(以下格式自行编排,编辑时删除)
概念:
预处理器(cpp)根据include指令,修改原始的c程序。得到一个以.i为后缀的预处理文件

作用:
将#include所包含的头文件直接加入到文本文件中。
对于一些宏定义,也在预处理阶段进行宏替换。
处理所有的预编译指令。
添加行号信息文件名信息,便于调试。
删除所有注释。
保留所有的#progma编译指令。

2.2在Ubuntu下预处理的命令
Gcc hello.c –E –o hello.i
(以下格式自行编排,编辑时删除)
应截图,展示预处理过程!

2.1

2.3 Hello的预处理结果解析
经过预处理,生成了hello.i中。在hello.i文件中包含了hello.c的main函数,并将#include所指向的文件添加进来。Hello.i文件长度增长,成为可以阅读的文本文件。

2.2

(以下格式自行编排,编辑时删除)
2.4 本章小结
本节描述了预处理的概念和具体的作用,在虚拟机中也对hello.c进行了实际的预处理,生成了hello.i文件,通过浏览hello.i文件更好的了解预处理的作用

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

(第2章0.5分)

第3章 编译
3.1 编译的概念与作用

(以下格式自行编排,编辑时删除)
编译:
编译器ccl将.i文件翻译成汇编文本文件.s文件,翻译后的文件为机器代码。
作用:
根据机器代码,深入理解程序,优化代码。
3.2 在Ubuntu下编译的命令
Gcc –S hello.i –o hello.s
(以下格式自行编排,编辑时删除)
应截图,展示编译过程!

3.1

3.3 Hello的编译结果解析

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

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

一、 数据
常量,以10进制保存。
Main,函数名。
局部变量,i。
Main函数参数,argv,argc。
二、 赋值操作
I = 0,对应机器代码movl $0, %eax。
三、 类型转换
Atoi,其定义为int atoi(const char* nptr)。通过调用atoi函数,将字符串转换成整数。
Sleep,其定义为unsigned sleep(unsigned seconds),即隐式的将有符号整形转换成无符号整型。
四、 算术操作
I++,即将i+1的值赋值给i。
五、 位操作

六、 关系操作
Argc != 4,cmpl $4, -20(%rbp)。通过cmpl比较,设置标志位。若其后为分支语句,则会有跳转je,jl等语句。
同样的,在for循环中,I < 8,也是同上。
七、 数组操作
Argv是char指针的指针,其内容是一组字符串的首地址。
八、 控制转移
通过比较语句cmp设置标志位,后通过跳转语句je,ja等,通过标志位决定是否跳转。
九、 函数操作
Main函数,第一个进入的用户编写的函数。其参数在进程创建时保存在上下文中。
函数调用,通过call语句调用。

3.4 本章小结
本节,对汇编的概念和作用进行了阐述,对汇编代码进行了分析和解释,并与C语言中的语句进行对比,生成了hello.s文件
(以下格式自行编排,编辑时删除)
(第3章2分)

第4章 汇编
4.1 汇编的概念与作用

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

注意:这儿的汇编是指从 .s 到 .o 即编译后的文件到生成机器语言二进制程序的过程。
概念:
汇编器(as)将汇编文件(hello.s)和翻译成机器语言指令,把这些指令打包成可重定位目标程序的格式,并将结果保存在二进制文件中(hello.o)
作用:
根据汇编指令和特定的平台,把汇编指令翻译成机器代码;合并各个节,合并符号表,生成.o文件

4.2 在Ubuntu下汇编的命令
(以下格式自行编排,编辑时删除)
应截图,展示汇编过程!
Gcc –c hello.s –o hello.o

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

ELF头:文件格式
.text:已经编译程序的机器代码
.rodata:只读数据
.data:初始化的全局和静态变量
.bss:未初始化的全局和静态变量
.symtab:符号表
.rel.text:一个.text节中位置的列表
.rel.data:别模块引用或定义的所有全局变量和重定位信息
.debug:调试符号表
.line:行号与.text的机器指令之间的映射
.strtab:一个字符串表
符号表中有hello.o中定义和引用的函数和全局变量,信息,其中包含大小、类型、名字等信息
4.4 Hello.o的结果解析
(以下格式自行编排,编辑时删除)
objdump -d -r hello.o 分析hello.o的反汇编,并请与第3章的 hello.s进行对照分析。
说明机器语言的构成,与汇编语言的映射关系。特别是机器语言中的操作数与汇编语言不一致,特别是分支转移函数调用等。

在源代码的机器及指令中加入了重定位的信息,包括类型和相对位置等,在连接时要修改他们的位置。
机器识别由操作码和操作数组成的机器语言
机器语言和汇编语言是一对一的映射关系
机器语言的跳转对函数的引用是使用与头部的偏移量来表示位置的,在汇编代码中使用的是一个一个的标号表示的
机器语言中的操作数使用的是十六进制格式,汇编语言使用的是十进制
机器语言的反汇编代码为每条语句都加上了具体的地址

4.2

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

(以下格式自行编排,编辑时删除)
(第4章1分)

第5章 链接
5.1 链接的概念与作用
(以下格式自行编排,编辑时删除)
注意:这儿的链接是指从 hello.o 到hello生成过程。
概念:
链接器ld将文件hello.o中的一些未定义的变量,函数,与其所在的.o文件进行合并,以及一些系统目标文件组合起来,生成可执行文件hello
作用:
合并各个.obj文件的节合并符号表,进行符号解析;进行符号地址的重定位;生成可执行文件

5.2 在Ubuntu下链接的命令
(以下格式自行编排,编辑时删除)
使用ld的链接命令,应截图,展示汇编过程! 注意不只连接hello.o文件
ld -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 /usr/lib/gcc/x86_64-linux-gnu/9/crtbegin.o hello.o -lc /usr/lib/gcc/x86_64-linux-gnu/9/crtend.o /usr/lib/x86_64-linux-gnu/crtn.o -z relro -o hello

5.1
5.3 可执行目标文件hello的格式
分析hello的ELF格式,用readelf等列出其各段的基本信息,包括各段的起始地址,大小等信息。
共29段。

5.2
如图,列举说明重要的节。
.init节定义了一个小函数,_init(),程序初始化代码调用它。起始地址为0x401000。
.text节,已编译的机器代码,起始地址为0x4010f0。
.rodata节,只读数据,在hello中,即指printf中的格式串。
.data,已初始化的全局变量和静态c变量。
.bss,未初始化的全局变量和静态c变量。
其下并没有.rel.text和.rel.data重定位节,因为经过链接的可执行文件,各处跳转已经完成了重定位。

5.3
5.4 hello的虚拟地址空间
使用edb加载hello,查看本进程的虚拟地址空间各段信息,并与5.3对照分析说明。
由程序头可知,hello各个段的虚拟地址空间地址和大小,如代码的虚拟地址为0x0大小为0x212
其余详见5.6。
5.5 链接的重定位过程分析
(以下格式自行编排,编辑时删除)
objdump -d -r hello 分析hello与hello.o的不同,说明链接的过程。
结合hello.o的重定位项目,分析hello中对其怎么重定位的。

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

一些库函数和外部调用函数都在文件中表述出来,引用是直接饮用,使用虚拟地址,均被包括到文件中,不是使用hello.o的间接引用
并且添加了一些其他的节如.init .plt等
链接过程:链接器为可重定位文件分配虚拟空间地址,进行重定位,然后按照符号表,把每个符号定义个内存位置联系起来,然后修改对这个扶摇的引用,让他们都指向这块内存,从而生成可执行程序
重定位:链接器将所有相同类型的节合并为一个节,然后链接器将运行时内存地址付给新的节和输入模块定义的每个符号,然后链接器利用可重定位条目,修改代码节和数据节中对符号的引用
5.6 hello的执行流程
(以下格式自行编排,编辑时删除)
使用edb执行hello,说明从加载hello到_start,到call main,以及程序终止的所有过程。请列出其调用与跳转的各个子程序名或程序地址。
加载hello,进入_init函数。如图。

5.4

5.5
后,根据一一对应关系,进入main函数。

5.6
结合edb与elf,有如下地址与跳转关系。
0x401233 puts
0x4011f6 puts
0x401200 exit
0x4010c0 atoi
0x4010e0 sleep
0x4010b0 getchar
5.7 Hello的动态链接分析
(以下格式自行编排,编辑时删除)
分析hello程序的动态链接项目,通过edb调试,分析在dl_init前后,这些项目的内容变化。要截图标识说明。
在调用共享库函数时,编译器没有办法预测这个函数的运行时地址,因为定义它的共享模块在运行时可以加载到任意位置。正常的方法是为该引用生成一条重定位记录,然后动态链接器在程序加载的时候再解析它。GNU编译系统使用延迟绑定,将过程地址的绑定推迟到第一次调用该过程时。
5.8 本章小结
本章主要介绍了linux下hello链接的方法、过程和结果及运行结果,分析了加载时重定位的共享库函数的重定位过程。
(以下格式自行编排,编辑时删除)
(第5章1分)

第6章 hello进程管理
6.1 进程的概念与作用
(以下格式自行编排,编辑时删除)
概念:进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
作用:进程作为一个执行中程序的实例,系统中每个程序都运行在某个进程的上下文中,上下文是由程序正确运行所需的状态组成的。这个状态包括存放在内存中的程序的代码和数据,它的栈、通用目的寄存器的内容、程序计数器、环境变量以及打开文件描述符的集合。
6.2 简述壳Shell-bash的作用与处理流程
(以下格式自行编排,编辑时删除)
作用:是一种交互型的应用级程序,是Linux的外壳,提供了一个界面,用户可以通过这界面访问操作系统内核。
流程:
1)从终端读入输入的命令。
2)将输入字符串切分获得所有的参数。
3)如果是内置命令则立即执行。
4)否则调用相应的程序为其分配子进程并运行。
5)shell应该接受键盘输入信号,并对这些信号进行相应处理。
6)若是后台程序,则调用execve执行,若不是,则使用wait等待。
6.3 Hello的fork进程创建过程
(以下格式自行编排,编辑时删除)
在终端中输入命令,shell接受并判断命令是否为内置命令。若是,则执行。若不是,则调用fork创建子进程。通过fork,子进程与父进程有着同样的虚拟地址空间,相同却又相互独立。
6.4 Hello的execve过程
(以下格式自行编排,编辑时删除)
Frok之后子进程调用execve函数在当前进程的上下文中加载一个新的进程。程序加载并运行可执行目标文件,得到的参数列表argv和环境变量envp,传递给main函数。
6.5 Hello的进程执行
(以下格式自行编排,编辑时删除)
结合进程上下文信息、进程时间片,阐述进程调度的过程,用户态与核心态转换等等。
逻辑控制流:一系列程序计数器PC的值的序列叫做逻辑控制流,这些值唯一地对应于包含在程序的可执行目标文件中的指令,或是包含在运行时动态链接到程序的共享对象中的指令。
时间片:一个进程执行它的控制流的一部分的每一时间段叫做时间片。
用户模式和内核模式:shell使得用户可以有机会修改内核,所以需要设置一些防护措施来保护内核,如限制指令的类型和可以作用的范围。
上下文切换:上下文就是内核重新启动一个被抢占的进程所需要的状态,是一种比较高层次的异常控制流。
开始Hello运行在用户模式,收到信号后进入内核模式,运行信号处理程序,之后再返回用户模式。运行过程中,cpu不断切换上下文,使运行过程被切分成时间片,与其他进程交替占用cpu,实现进程的调度。
6.6 hello的异常与信号处理
(以下格式自行编排,编辑时删除)
hello执行过程中会出现哪几类异常,会产生哪些信号,又怎么处理的。
程序运行过程中可以按键盘,如不停乱按,包括回车,Ctrl-Z,Ctrl-C等,Ctrl-z后可以运行ps jobs pstree fg kill 等命令,请分别给出各命令及运行结截屏,说明异常与信号的处理。

运行过程中可能出现的异常种类由四种:中断、陷阱、故障、终止。
中断:来自I/O设备的信号,异步发生。硬件中断的异常处理程序被称为中断处理程序。
陷阱:是执行一条指令的结果。调用后返回到下一条指令。
故障:由错误情况引起,可能能被修正。修正成功则返回到引起故障的指令,否则终止程序。
终止:不可恢复,通常是硬件错误,这个程序会被终止。
6.7本章小结
(以下格式自行编排,编辑时删除)
本章介绍了进程的相关概念,描述了hello子进程fork和execve的过程,介绍了shell的一般处理流程和异常与信号处理。
(第6章1分)

第7章 hello的存储管理
7.1 hello的存储器地址空间
(以下格式自行编排,编辑时删除)
结合hello说明逻辑地址、线性地址、虚拟地址、物理地址的概念。
逻辑地址:格式为“段地址:偏移地址”,是CPU生成的地址,在内部和编程使用,并不唯一。
物理地址:加载到内存地址寄存器中的地址,内存单元的真正地址。CPU通过地址总线的寻址,找到真实的物理内存对应地址。在前端总线上传输的内存地址都是物理内存地址。
虚拟地址:保护模式下程序访问存储器所用的逻辑地址。
线性地址:逻辑地址向物理地址转化过程中的一步,逻辑地址经过段机制后转化为线性地址。
7.2 Intel逻辑地址到线性地址的变换-段式管理
(以下格式自行编排,编辑时删除)
分段功能在实模式和保护模式下有所不同。
实模式:逻辑地址=线性地址=实际的物理地址。段寄存器存放真实段基址,同时给出32位地址偏移量,并且可以访问真实物理内存。
保护模式:线性地址还需要经过分页机制才能够得到物理地址,线性地址也需要逻辑地址通过段机制来得到。
在保护模式下,控制寄存器CR0中的最高位PG位控制分页管理机制是否生效。如果PG=1,分页机制生效,把线性地址转换为物理地址。如果PG=0,分页机制无效,线性地址就直接作为物理地址。必须注意,只有在保护方式下分页机制才可能生效。只有在保证使PE位为1的前提下,才能够使PG位为1,否则将引起通用保护故障。
段寄存器用于存放段选择符,通过段选择符可以得到对应段的首地址。处理器在通过段式管理寻址时,首先通过段描述符得到段基址,然后与偏移量结合得到线性地址,从而得到了虚拟地址。
7.3 Hello的线性地址到物理地址的变换-页式管理
(以下格式自行编排,编辑时删除)
将各进程的虚拟空间划分成若干个长度相等的页(page),页式管理把内存空间按页的大小划分成片或者页面(page frame),然后把页式虚拟地址与内存地址建立一一对应页表,并用相应的硬件地址变换机构,来解决离散地址变换问题。页式管理采用请求调页或预调页技术实现了内外存存储器的统一管理。
7.4 TLB与四级页表支持下的VA到PA的变换
(以下格式自行编排,编辑时删除)
TLB是MMU中对与PTE的缓存,采用组相联的方式;

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

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

通过内存地址的组索引获得值,如果对应的值是data则像L1 d-cache对应组中查找,如果是指令,则向L1 i-cache对应组中查找。将L1对应组中的每一行的标记位进行对比,如果相同并且有效位为1则命中,获得偏移量,取出相应字节,否则不命中,向下一级cache寻找,最后到向内存中寻找。
7.6 hello进程fork时的内存映射
(以下格式自行编排,编辑时删除)
内存映射为每个进程都创建独立得虚拟地址空间。当fork函数被当前进程调用时,内核位新进程创建各种数据结构,并分配给他一个唯一的PID。通过创建进程得mm_struct,区域结构和页表得原样副本,他将2个进程中得每个页面都标记为只读。并将2个进程中得每个区域结构都标记为写时复制。 fork在新进程中返回时,新进程现在得虚拟内存刚好和调用fork时存在得虚拟空间内存相同。当2个进程中,有一个要对其中得私有部分进行写操作时,会触发只读保护,会触发故障处理程序,将要写得页复制一份,并恢复他写得权限。回到原来程序得当前指令,进行写操作。对于共享得部分,不同进程得不同虚拟页会映射到同一个内存物理页。
7.7 hello进程execve时的内存映射
(以下格式自行编排,编辑时删除)
1.删除已存在的用户区域。删除当前继承虚拟地址的用户部分中的已存在的区域结构
2.映射私有区域。 为新程序的代码,数据,bss和栈区域创建新的区域结构。所有这些新的区域都是私有的、写时复制的。代码和数据区域被映射为hello.out文件中的.text和.data取.bss区域时请求二进制零的。
3.映射共享区域。如果hello.out程序与共享对象(或目标)链接,比如标准c库 libc.so。那么这些对象都是动态链接这个程序的, 然后再映射到用户虚拟地址空间中的共享区域内。
4.设置程序计数器(PC)。execve做的最后一件事就是设置当前进程上下文中的程序计数器,使之指向代码区域的入口点。
7.8 缺页故障与缺页中断处理
(以下格式自行编排,编辑时删除)
1.缺页:将DRAM的缓存不命中成为缺页。
2.缺页故障:当cpu引用的虚拟地址所在的虚拟页的PTE有效位为0,即所对应的虚拟页不再内存,会引发缺页故障异常。
3.缺页中断处理: 缺页异常调用内核的缺页异常处理程序.程序选择内存中的一个页作为牺牲页。如果这个页被修改过(修改位被设置),则将该页写回磁盘。然后按照目标虚拟页的PTE的磁盘地址,将磁盘的页取出放内存中,同时修改PTE。 然后返回程序中断处的当前指令,继续请求访问该虚拟地址。
7.9动态存储分配管理
(以下格式自行编排,编辑时删除)
动态内存通过动态内存分配器进行管理。
动态内存分配器维护着一个进程的虚拟内存区域,称为堆.系统之间细节不同。但是不是共通性。假设堆使一个请求二进制零的区域,他紧接再未初始化的数据区域后开始, 并向更高地址处生长。 对于每一个进程,内核维护一个边量brk作为堆的顶部。
分配器将堆视为一组不同大小的块的集合来维护。 每个块都是一个连续的虚拟内存片,要么是已分配的,要么是空闲的。 已分配的块显示地保留,供应用程序使用,空闲块可用来分配。 空闲块保持空闲,直到他显示地被应用所分配。 一个已分配的块保持已分配的状态,直到他被释放。这种释放要么是应用程序显示的执行,要么是内存分配器自身隐式执行的。
基本方法:
隐式空闲链表: 每个块包含一个4字的头部和4字的相同信息的尾部,分别再块的开始和结尾,其中存储了块的大小和块的分配位。(如果式双子对齐后3位储存分配位),分配位为1则表示该块已分配;位0则表示该块式空闲的。 每次寻找会根据的堆的头部分配位判断是否是空闲的,大小值判断是否适合存储,并根据大小信息找到一个块的块头。尾部则是在空闲块合并时,提供前一个块的大小和是否位空闲块的信息。
显示空闲链表:再空闲块中,除了头部和尾部,还存在指向前一个空闲块和后一个空闲块的2个指针,通过指针可以找到所有的空闲块。
策略:
首次分配:每一次分配,都从堆的开始寻找空闲块,直到找到一个可以存储的下的空闲块,就分配该块。
下次分配:每次分配都从上次的地方开始寻找空闲块,一旦找到可以存储的下的空间块,就分配该块。
最佳分配:遍历所有的空闲块,找到可以存储的下,且最小的块进行分配。
所有的分配中,如果找不到合适的块,就会调用extend函数,扩大堆,增大brk。
7.10本章小结
(以下格式自行编排,编辑时删除)
本章主要介绍了程序的存储结构,进程的虚拟地址空间映射,虚拟地址到物理地址的转换,段式管理及页式管理的方法,高速缓存的利用方法以及运行时的动态内存分配。
(第7章 2分)

第8章 hello的IO管理
8.1 Linux的IO设备管理方法
(以下格式自行编排,编辑时删除)
设备的模型化:文件
设备管理:unix io接口
设备的模型化:所有的IO设备都被模型化为文件,而所有的输入和输出都被当做对相应文件的读和写来执行,这种将设备优雅地映射为文件的方式,允许 Linux 内核引出一个简单低级的应用接口,称为 Unix I/O。
8.2 简述Unix IO接口及其函数
(以下格式自行编排,编辑时删除)
Linux以文件的方式对I/O设备进行读写,将设备均映射为文件。对文件的操作,内核提供了一种简单、低级的应用接口,即Unix I/O接口。
所有输入输出都按以下一致的方式执行:
打开文件。一个应用程序通过要求内核打开相应的文件,来宣告它想要访问一个I/O设备,内核返回一个小的非负整数,叫做描述符,它在后续对此文件的所有操作中标识这个文件,内核记录有关这个打开文件的所有信息。
Shell创建的每个进程都有三个打开的文件:标准输入(stdin),标准输出(stdout),标准错误(stderr)。
改变当前的文件位置:对于每个打开的文件,内核保持着一个文件位置k,初始为0,这个文件位置是从文件开头起始的字节偏移量,应用程序能够通过执行seek,显式地将改变当前文件位置k。
读写文件:一个读操作就是从文件复制n>0个字节到内存,从当前文件位置k开始,然后将k增加到k+n,给定一个大小为m字节的而文件,当k>=m时,触发EOF。类似一个写操作就是从内存中复制n>0个字节到一个文件,从当前文件位置k开始,然后更新k。
关闭文件,内核释放文件打开时创建的数据结构,并将这个描述符恢复到可用的描述符池中去。
具体实现函数及其参数要求:
打开文件:int open(char *filename,int flags,mode_t mode); open函数将filename转换为一个文件描述符,并且返回描述符数字,返回的描述符总是在进程中当前没有打开的最小描述符,flags参数指明了进程打算如何访问这个文件,而mode参数指定了新文件的访问权限位。
关闭文件:int close(int fd); fd是需要关闭的文件的描述符,close返回操作结果。
读文件:ssize_t read(int fd,void *buf,size_t n) read函数从描述符为fd的当前文件位置赋值最多n个字节到内存位置buf。返回值-1表示一个错误,0表示EOF,否则返回值表示的是实际传送的字节数量。
写文件:ssize_t write(int fd,const void *buf,size_t n);
write函数从内存位置buf复制至多n个字节到描述符为fd的当前文件位置。write函数从内存位置buf复制至多n个字节到描述符为fd的当前文件位置。
8.3 printf的实现分析
(以下格式自行编排,编辑时删除)
https://www.cnblogs.com/pianist/p/3315801.html
从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall等.
字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。
显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。
8.4 getchar的实现分析
(以下格式自行编排,编辑时删除)
异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。
getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。
8.5本章小结
(以下格式自行编排,编辑时删除)
本节关于io管理。Linux通过io文件化,统一管理io,同时具体描述了部分io接口函数。
(第8章1分)
结论
用计算机系统的语言,逐条总结hello所经历的过程。
你对计算机系统的设计与实现的深切感悟,你的创新理念,如新的设计与实现方法。

  1. 预处理:解析替换#开头的语句,生成hello.i。
  2. 编译:将代码文件翻译为汇编语言。
  3. 汇编:将汇编语言翻译成机器代码。
  4. 链接:连接器将可重定位目标文件或动态链接动态库.so,或链接静态库.a,或链接其他可重定位目标文件,生成了最终的可执行目标文件。
  5. 进程:shell处理命令,并创建子进程,加载可执行目标程序,将hello加载至内存中。
  6. 程序运行:程序逐语句运行,cpu取指,译码,期间io函数的调用,处理来自外部的信号。
  7. 异常处理:程序运行时,键盘输入Ctrl^z等,处理信号,并调用相应的处理函数。
  8. 终结:当hello运行完成后,父进程回收子进程,hello消失。
    (结论0分,缺失 -1分,根据内容酌情加分)

附件
列出所有的中间产物的文件名,并予以说明起作用。
hello.c C语言源程序
hello.i 预处理得到的文本文件
hello.s 编译得到的汇编程序
hello.o 汇编后生成的可重定位目标文件
hello 连接后生成的可执行目标文件

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

参考文献
为完成本次大作业你翻阅的书籍与网站等
[1] 林来兴. 空间控制技术[M]. 北京:中国宇航出版社,1992:25-42.
[2] 辛希孟. 信息技术与信息服务国际研讨会论文集:A集[C]. 北京:中国科学出版社,1999.
[3] 赵耀东. 新时代的工业工程师[M/OL]. 台北:天下文化出版社,1998 [1998-09-26]. http://www.ie.nthu.edu.tw/info/ie.newie.htm(Big5).
[4] 谌颖. 空间交会控制理论与方法研究[D]. 哈尔滨:哈尔滨工业大学,1992:8-13.
[5] KANAMORI H. Shaking Without Quaking[J]. Science,1998,279(5359):2063-2064.
[6] CHRISTINE M. Plant Physiology: Plant Biology in the Genome Era[J/OL]. Science,1998,281:331-332[1998-09-23]. http://www.sciencemag.org/cgi/ collection/anatmorp.
(参考文献0分,缺失 -1分)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值