计算机系统
大作业
题 目 程序人生-Hello’s P2P
计算机科学与技术学院
2020年3月
摘 要
摘要是论文内容的高度概括,应具有独立性和自含性,即不阅读论文的全文,就能获得必要的信息。摘要应包括本论文的目的、主要内容、方法、成果及其理论与实际意义。摘要中不宜使用公式、结构式、图表和非公知公用的符号与术语,不标注引用文献编号,同时避免将摘要写成目录式的内容介绍。
关键词:关键词1;关键词2;……;
(摘要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:即“From Program to Process”,字面意义便是从程序到过程。hello.c(program),经过预处理、编译、汇编、链接,历经艰辛-神秘-高贵-欣喜,才成为了可执行文件hello
O2O:即“From Zero-0 to Zero-0”,字面上来看便是从零到零。Hello在bash中通过OS经过fork,execve,mmap等过程,才得以执行,输出,最后结束。
1.2 环境与工具
(列出你为编写本论文,折腾Hello的整个过程中,使用的软硬件环境,以及开发与调试工具。)
硬件环境:16GBDDR4双通道内存,i7-8750H,1TBHDD, 256GBSSD
软件环境:Win10 64位;VMware15.5.0;Ubuntu 19.04;
开发与调试工具:GCC;GDB;CB;VS;EDB
1.3 中间结果
(列出你为编写本论文,生成的中间结果文件的名字,文件的作用等。)
Hello.c 源文件
Hello.o 目标代码文件
Hello 最后链接生成的可执行文件
1.4 本章小结
Hello是每个程序员最开始接触的程序,但它的生成执行过程并没有那么简单。短短的一生中还包含了“P2P”,“O2O”的内容。
(第1章0.5分)
第2章 预处理
2.1 预处理的概念与作用
C预处理器是在程序执行之前查看程序,根据程序中的预处理指令,把符号缩写替换成其表示的内容。预处理器可以包含程序所需的其他文件,也可以选择让编译器查看哪些代码。其工作主要就是把一些文本转换成另外一些文本。
2.2在Ubuntu下预处理的命令
应截图,展示预处理过程!
gcc -E hello.c -o hello.i
2.3 Hello的预处理结果解析
2.4 本章小结
简要介绍了预处理的概念和作用,并在Ubuntu下进行了实操。
(第2章0.5分)
第3章 编译
3.1 编译的概念与作用
注意:这儿的编译是指从 .i 到 .s 即预处理后的文件到生成汇编语言程序
编译器会把源代码转换成可执行程序的代码,这里的编译是将hello.i翻译成一个ASCII汇编语言文件main.s ,也就是把代码翻译成汇编语言。
3.2 在Ubuntu下编译的命令
gcc -S hello.i -o hello.s
应截图,展示编译过程!
3.3 Hello的编译结果解析
3.3.1数据
从源程序中可以看出。i为局部变量且赋值为0,可以推测其存储在寄存器-4(%rbp)中
只读数据段保存着源程序中"用法: Hello 学号 姓名 秒数!\n","Hello %s %s\n"两个字符串
3.3.2赋值
利用movl指令给i赋值为0
3.3.3算术操作
对应着源程序的i++内容
3.3.4数组/指针/结构操作
循环体调用元素
3.3.5关系操作
对应着源程序的argc!=4
对应着源程序的i<8
3.3.6控制转移
对应着源程序for(i=0;i<8;i++)
3.4 本章小结
本章主要涉及了编译的概念与具体过程,并且分析了c语言中数据,算术操作等在汇编语言中的具体执行方式。
(第3章2分)
第4章 汇编
4.1 汇编的概念与作用
注意:这儿的汇编是指从 .s 到 .o 即编译后的文件到生成机器语言二进制程序的过程。
编译器会把源代码转换成可执行程序的代码,而这里的汇编指的是驱动程序运行汇编器(as),将hello.s翻译成一个可重定位目标文件hello.o,也就是将汇编语言转换成机器指令。
4.2 在Ubuntu下汇编的命令
应截图,展示汇编过程!
gcc -c hello.s -o hello.o
4.3 可重定位目标elf格式
(分析hello.o的ELF格式,用readelf等列出其各节的基本信息,特别是重定位项目分析。)
首先利用readelf -a hello.o命令查看信息
4.3.1 ELF头,描述了生成该文件的系统的字的大小和字节顺序
4.3.2 节,在ELF头和节头部表之间的都是节,典型的ELF可重定位目标代码文件包含以下几个节
.text 已经编译程序的机器代码
.rodata 只读数据
.data 已经初始化的全局和静态C变量
.bss 未初始化的全局和静态C变量
.symtab 一个符号表
.rel.text 一个.text节中位置的列表
.rel.data 被模块引用或定义的所有全局变量的重定位信息,
.debug 一个调试符号表
.line 原始C源程序中的行号和,text节中机器指令之间的映射。只有以-g选项调用编译器驱动程序时,才会得到这张表。
.strtab 一个字符串表,其内容包括.symtab和.debug节中的符号表,以及节头部中的节名字。字符串表就是以null结尾的字符串的序列。
4.3.3重定位节
包含.text中位置的列表,可执行目标文件中并不需要重定位 信息,因此通常忽略。
包含.eh_frame的位置信息
4.3.4符号表,包含可重定位模块m定义和引用的符号的信息
4.4 Hello.o的结果解析
(objdump -d -r hello.o 分析hello.o的反汇编,并请与第3章的 hello.s进行对照分析。
说明机器语言的构成,与汇编语言的映射关系。特别是机器语言中的操作数与汇编语言不一致,特别是分支转移函数调用等。)
4.4.1构成与映射关系
观察可以发现,hello.o的反汇编与hello.s相比,有着很多的相同部分,但是hello.o的反汇编在左边多出了一部分机器指令和其对应的位置。
4.4.2分支转移
在hello.s中都是通过L2/L3/L4来实现分支转移,但是在hello.o的反汇编中则是直接给出具体的位置来实现分支转移。
4.4.3函数调用
在hello.s调用函数是通过call+函数名,但是在hello.o的反汇编中则是通过call+具体位置。
4.5 本章小结
本章主要注重与从汇编语言到机器指令阶段的编译过程,并且阐释了一个可重定位目标文件的构成。并且通过反汇编来观察它与ASCII码汇编语言文件之间的联系和不同之处。
(第4章1分)
第5章 链接
5.1 链接的概念与作用
(注意:这儿的链接是指从 hello.o 到hello生成过程。)
链接就是将各种代码和数据片段收集并组合成为一个单一文件的过程,这个文件可被加载(复制)到内存并执行
这里链接的作用便是通过链接器程序ld将可重定位文件hello.o和sum.o以及一些必要的系统目标文件组合起来,创建出一个可执行文件hello的过程。
5.2 在Ubuntu下链接的命令
使用ld的链接命令,应截图,展示汇编过程! 注意不只连接hello.o文件
5.3 可执行目标文件hello的格式
(分析hello的ELF格式,用readelf等列出其各段的基本信息,包括各段的起始地址,大小等信息。)
首先利用readelf -a hello命令查看信息
5.3.1 ELF头
5.3.2 节
观察可以发现,与hello.o相比,hello的节头多出了12个部分
5.3.3 程序头
5.3.4符号表
5.4 hello的虚拟地址空间
(使用edb加载hello,查看本进程的虚拟地址空间各段信息,并与5.3对照分析说明。)
edb中的具体地址对应了ELF头以及节中的映射关系。
5.5 链接的重定位过程分析
与hello.o相比,hello的反汇编文件明显是增多了。
可以发现hello的反汇编文件中增加了很多如printf函数的运用,并且也增加了很多section,
并且发现hello的反汇编文件和hello.i有一定相似之处,都是通过call+函数名来调用函数,而hello.s的反汇编文件则是通过call+地址来调用函数。
5.6 hello的执行流程
使用edb执行hello,说明从加载hello到_start,到call main,以及程序终止的所有过程。请列出其调用与跳转的各个子程序名或程序地址。
5.7 Hello的动态链接分析
共享库(shared library)是致力于解决静态库缺陷的一个现代创新产物。共享库是一个目标模块,在运行或加载时,可以加载到任意的内存地址,并和一个在内存中的程序链接起来,这个过程称为动态链接(dynamic linking),是由一个叫做动态莲接器(dynamic linker)的程序来执行的。共享库也称为共享目标(shared object),在Linux系统中通常用.so后缀来表示。微软的操作系统大量地使用了共享库,它们称为DLL(动态链接库)。
分析hello程序的动态链接项目,通过edb调试,分析在dl_init前后,这些项目的内容变化。要截图标识说明。
5.8 本章小结
本章主要介绍了链接的相关内容,链接生成了hello并分析其反汇编文件, 动态链接,重定位流程等。
(第5章1分)
第6章 hello进程管理
6.1 进程的概念与作用
进程的经典定义就是一个执行中程序的实例。系统中每个程序都运行在某个进程的上下文(由程序正确运行所需的状态组成的)中。
。
6.2 简述壳Shell-bash的作用与处理流程
每次用户通过shell输入一个可执行目标文件的名字,运行程序时,shell就会创建一个新的进程,然后在这个新进程的上下文中运行它们自己的代码或其他应用程序。应用程序也能够创建新进程,并且在这个新进程的上下文中运行它们自己的代码或者其他应用程序。
6.3 Hello的fork进程创建过程
在Ubuntu系统中我们打开终端输入./hello,系统判定这不是一个内置命令而是一个可执行文件,shell会通过fork函数生成两个几乎完全一样的进程,二者PID不同。
6.4 Hello的execve过程
Execve函数会在当前进程的上下文中加载并运行一个新程序,它会加载并运行可执行目标文件filename,且带参数列表argv和环境变量列表envp。只有当出现错误时,例如找不到filename,execve才会返回到调用程序。所以,于fork一次调用返回两次不同,execve调用一次并不返回。
6.5 Hello的进程执行
结合进程上下文信息、进程时间片,阐述进程调度的过程,用户态与核心态转换等等。
操作系统内核使用一种称为上下文切换的较高层形式的异常控制流来实现多任务。上下文切换机制是建立在较低层异常机制之上的:
6.6 hello的异常与信号处理
( hello执行过程中会出现哪几类异常,会产生哪些信号,又怎么处理的。)
(程序运行过程中可以按键盘,如不停乱按,包括回车,Ctrl-Z,Ctrl-C等,Ctrl-z后可以运行ps jobs pstree fg kill 等命令,请分别给出各命令及运行结截屏,说明异常与信号的处理。)
异常可以分为四类,中断(interrupt),陷阱(trap),故障(fault)和终止(abort)
信号则有如下30种
6.6.1 键盘乱按
在程序运行过程中,第一次键盘乱按,频率过快,导致了虚拟机卡住。
再一次尝试,键盘乱按,输入字符会储存在一列中,在按下回收之后,程序会直接停止。
6.6.2 回车
在程序运行过程中直接按下回车,发现程序仍然在运行,只是在终端显示页面会跳行。
6.6.3 ctrl+z
进程直接停止
ps
jobs
pstree
fg程序再启动
Kill杀死程序
6.6.4 ctrl+c
也会导致进程终止
6.7本章小结
本章主要介绍了进程的定义和作用,并且分析了不同异常状况和产生的信号,也分析了hello的fork与execve。
(第6章1分)
第7章 hello的存储管理
7.1 hello的存储器地址空间
结合hello说明逻辑地址、线性地址、虚拟地址、物理地址的概念。
逻辑地址:例如hello.o的反汇编文件左边就是逻辑地址,是在机器语言指令中用来指定一个操作数或者指令的地址。
线性地址:也并不是真实的地址,需要变换才能得到物理地址。逻辑地址和基地址相加就可看作是线性地址。
虚拟地址:在一个带虚拟内存的系统中,CPU有N=2n个地址的虚拟地址空间,在其中生成的地址便是虚拟地址。Hello里的虚拟地址也是如此。
物理地址:物理地址空间对应于系统中物理内存的M个字节,{0,1,2,3,….,M-1},其中每一个字节都有一个物理地址。Hello里的虚拟地址也对应着其物理地址。
7.2 Intel逻辑地址到线性地址的变换-段式管理
逻辑地址由两部分组成:段标识符和段内偏移量
从逻辑地址到线性地址的变换要经过一下几步:
1.首先对于一个完整的逻辑地址,将其分解,
2.判断T1字符,区分是LDT还是GDT。
3.查找段描述符,找到基地址。
4.将逻辑地址与基地址相加,就是要转换的线性地址了。
7.3 Hello的线性地址到物理地址的变换-页式管理
MMU利用VPN来选择适当的PTE。例如VPN0选择 PTE0,VPN1选择PTE1,以此类推。将页表条目中物理页号和虚拟地址中的VPO串联起来,就可以得到相应的物理地址。
7.4 TLB与四级页表支持下的VA到PA的变换
(以下格式自行编排,编辑时删除)
TLB是一个小的,虚拟寻址的缓存,其中每一行都保存着一个由单个PTE组成的快,TLB通常有着高度的相联度。
用于组选择和行匹配的索引和标记字段是从虚拟地址中的虚拟页号中提取出来的。TLB索引(TLBI)是由VPN的t个最低位组成的,而TLB标记(TLBT)则是由VPN中剩余的位组成的。
TLB能减少不必要的时间开销
而这里VPN被分为四段,一步步向下寻址,越往下对应的条目也就越小,经过四层寻址之后再得到结果。
7.5 三级Cache支持下的物理内存访问
得到物理地址之后就将其拆分并且在L1中去找,未命中之后再去L2和L3中去找,命中之后返回
7.6 hello进程fork时的内存映射
创建当前进程的内存描述符,区域结构描述符,页表原样副本。并将两个页面都标记为只读,并且把两个进程的区域结构描述符都标记为写时复制。
7.7 hello进程execve时的内存映射
异常处理程序返回后还会重新启动导致缺页的指令。
7.9动态存储分配管理
Printf会调用malloc,请简述动态内存管理的基本方法与策略。
动态存储分配可以帮助我们为C程序获得额外的虚拟内存空间。
动态内存分配器维护着一个进程的虚拟内存区域,称为堆。
分配器有两种基本风格:显示分配器和隐式分配器
C标准库提供了一个称为malloc程序包的显示分配器,程序可以通过调用malloc函数来从堆中分配块。每个块就是一个连续的虚拟内存篇,要么时已分配的,要么就是空闲的。空闲的就可以用作分配。
分配器通常有两个性能目标:最大化吞吐率和最大化内存利用率。
7.9.1 隐式空闲链表
空闲块是通过头部中的大小字段隐含地连接着,分配器可以通过遍历堆中所有块,从而间接地遍历整个空闲块的集合。值得注意的是,我们需要某种特殊标记的结束块。块分配与堆块的总数呈线性关系。
7.9.2 显式空闲链表
程序不需要一个空闲块的主体,所以实现这个数据结构的指针就可以存放在这些空闲块的主体里面。例如堆可以组织成一个双向空闲链表,在每个空闲块中都包含一个前驱pred和后继succ指针。
7.10本章小结
本章更加侧重于程序的存储结构,介绍了寻址及地址转换,缺页故障处理以及动态内存分配等。
(第7章 2分)
第8章 hello的IO管理
8.1 Linux的IO设备管理方法
设备的模型化:文件
设备管理:unix io接口
一个Linux文件就是一个m个字节的序列:
所有的I/O设备(例如网络、磁盘和终端)都被模型化为文件,而所有的输入和输出都被当作对相应文件的读和写来执行。这种将设备优雅地映射为文件的方式,允许Linux内核引出一个简单、低级的应用接口,称为Unix1/O,这使得所有的输入和输出都能以一种统一且一致的方式来执行:
8.2 简述Unix IO接口及其函数
1.打开文件。一个应用程序通过要求内核打开相应的文件,来宣告它想要访问一个I/O设备。内核返回一个小的非负整数,叫做描述符,它在后续对此文件的所有操作中标识这个文件。内核记录有关这个打开文件的所有信息。应用程序只需记住这个描述符,该阶段主要通过open函数来实现。
2.Linux shell创建的每个进程开始时都有三个打开的文件:标准输入(描述符为0)、标准输出(描述符为1)和标准错误(描述符为2).头文件< unistd.h>定义了常量STDIN_FILENO, STDOUT_FILENO和STDERR_FILENO,它们可用来代替显式的描述符值.
3.改变当前的文件位置。对于每个打开的文件,内核保持着一个文件位置k,初始为0.这个文件位置是从文件开头起始的字节偏移量。应用程序能够通过执行seek操作,显式地设置文件的当前位置为k。
4.读写文件。一个读操作就是从文件复制n>0个字节到内存, 从当前文件位置k开始,然后将k增加到k+n.给定一个大小为m字节的文件,当k≥m时执行读操作会触发一个称为end-of-file(EOF)的条件,应用程序能检测到这个条件。在文件结尾处并设有明确的“EOF符号”。
类似地,写操作就是从内存复制n>0个字节到一个文件,从当前文件位置k开始,然后更新k。
该阶段主要通过read和write函数来执行输入和输出
5.关闭文件。当应用完成了对文件的访问之后,它就通知内核关闭这个文件。作为响应,内核释放文件打开时创建的数据结构,并将这个描述符恢复到可用的描述符池中。无论一个进程因为何种原因终止时,内核都会关闭所有打开的文件并释放它们的内存资源。
8.3 printf的实现分析
https://www.cnblogs.com/pianist/p/3315801.html
Printf函数体如下
int printf(const char *fmt, …)
{
int i;
char buf[256];
va_list arg = (va_list)((char*)(&fmt) + 4);
i = vsprintf(buf, fmt, arg);
write(buf, i);
return i;
}
其中i = vsprintf(buf, fmt, arg),write(buf, i)调用了两个函数
vsprintf(buf, fmt, arg)函数如下
int vsprintf(char *buf, const char fmt, va_list args)
{
char p;
char tmp[256];
va_list p_next_arg = args;
for (p=buf;*fmt;fmt++) {
if (*fmt != '%') {
*p++ = *fmt;
continue;
}
fmt++;
switch (*fmt) {
case 'x':
itoa(tmp, *((int*)p_next_arg));
strcpy(p, tmp);
p_next_arg += 4;
p += strlen(tmp);
break;
case 's':
break;
default:
break;
}
}
return (p - buf);
}
它接受一个格式化的命令,并把指定的匹配的参数格式化输出,i = vsprintf(buf, fmt, arg)就是返回打印的字符串的长度。
Write函数如下
write:
mov eax, _NR_write
mov ebx, [esp + 4]
mov ecx, [esp + 8]
int INT_VECTOR_SYS_CALL
其作用就是接受前面返回的字符串长度,并将参数存放在寄存器中,再通过系统调用sys_call这个函数。
从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall.
字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。
显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。
8.4 getchar的实现分析
getchar主要通过调用read函数来读取字符串并返回。
异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。
getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。
8.5本章小结
本章主要介绍了Linux的I/O管理方法,接口及函数,还有printf与getchar的实现方式。
(第8章1分)
结论
用计算机系统的语言,逐条总结hello所经历的过程。
附件
列出所有的中间产物的文件名,并予以说明起作用。
(附件0分,缺失 -1分)
hello.c:源程序文件
hello.i:由hello.c预处理而成的ASCII码的中间文件
hello.s:由hello.i编译成的一个ASCII汇编语言文件,对应汇编语言
hello.o:由hello.s编译而成的一个可重定位目标文件,对应机器指令
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.
[7] C Primer Plus 第六版
[8] 深入理解计算机系统 第三版
(参考文献0分,缺失 -1分)