计算机系统
大作业
题 目 程序人生-Hello’s P2P
专 业 计算机科学与技术
学 号 2021110769
班 级 2103102
学 生 甘浩言
指 导 教 师 刘宏伟
计算机科学与技术学院
2022年5月
摘 要
本文章介绍了程序的一生,讲述其经历预处理,编译,汇编,链接,进程方面的内容。文章利用了x86-64的linux系统作为开发平台,ubuntu作为软件环境,利用了GDB,EDB,readelf,objdump等开发工具完成了对于程序一生的详细经历和具体研究
关键词:预处理;编译;汇编;链接;进程;
(摘要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,从程序到进程。
O2O: From Zero-0 to Zero-0,程序执行前在内存中不存在,程序执行后相关痕迹也被清理。
编译器通过预处理、编译、汇编、链接将程序从代码文件生成可执行文件。在shell中输入./hello后,shell就会调用fork()创建一个进程。
shell通过execve()加载程序,调用mmap使程序得以利用内存,通过CPU分配时间片使程序可以利用CPU的流水线。Os与mmu利用TLB、4级页表、3级Cache,Pagefile等方式为程序运行进行加速,IO管理能处理键盘、主板、显卡、屏幕的信号并使程序可以处理各种情况,最后程序运行完成后,shell回收这个进程。
1.2 环境与工具
列出你为编写本论文,折腾Hello的整个过程中,使用的软硬件环境,以及开发与调试工具。
硬件环境:联想r7000,amd r5600(x86-64,3.3GHz),16G DDR4内存,512G SSD
软件环境:VMWARE, Ubuntu
开发及调试工具:GDB,EDB,readelf,objdump
1.3 中间结果
列出你为编写本论文,生成的中间结果文件的名字,文件的作用等。
名字:hello.i,作用:代码文件经预处理后生成的文件
名字:hello.s, 作用:hello.i经编译后产生的文件,可以了解编译过程及汇编语言。
名字:hello.o, 作用;hello.s汇编后生成的文件,可用于链接以及对elf的查看
名字:hello,作用:hello.o链接后生成的文件
1.4 本章小结
本章介绍了Hello的P2P,020的整个过程,以及使用的软硬件环境,以及开发与调试工具,再加上生成的中间结果文件的名字,文件的作用。
(第1章0.5分)
第2章 预处理
2.1 预处理的概念与作用
预处理概念:预处理器根据以#开头的命令,修改原始的C语言程序。
预处理作用:1.将#后包含的系统头文件的内容插入到文件文本中。
2.根据#define后的宏定义作替换。
3.根据#ifdef,#ifndef等指令进行条件编译。
4.生成.i文本文件。
2.2在Ubuntu下预处理的命令
应截图,展示预处理过程!
图2.1-预处理命令
上述为Ubuntu上进行预处理应输入的命令
图2.2-预处理后的文件
图2.3-.i文件的内容
生成的.i文件及部分内容。
2.3 Hello的预处理结果解析
图2.4-.i文件的内容
对文件内容进行分析,可以看出预处理后系统将头文件的文本内容加入到了代码当中。在未展示出来的文本内容中,依旧保持源代码的内容,同时还有头文件的绝对路径以及外部函数的引用再加上结构体定义和数据类型声明。
2.4 本章小结
本章讲述了预处理的概念以及作用,还展示了如何进行预处理以及生成文件和文件的部分内容,并对生成的文件内容进行分析。
(第2章0.5分)
第3章 编译
3.1 编译的概念与作用
注意:这儿的编译是指从 .i 到 .s 即预处理后的文件到生成汇编语言程序
编译概念:编译器将文本文件hello.i翻译成文本文件hello.s,它包含一个汇编语言程序。
编译作用:将文本文件转换为汇编语言程序,从不同高级程序语言转换为通用的输出语言-低级机器语言指令
3.2 在Ubuntu下编译的命令
图3.1-编译命令
上述为编译指令
图3.2-编译文件
图3.3-.s文件内容
上述为产生的.s 文件及部分文件内容。
应截图,展示编译过程!
3.3 Hello的编译结果解析
此部分是重点,说明编译器是怎么处理C语言的各个数据类型以及各类操作的。应分3.3.1~ 3.3.x等按照类型和操作进行分析,只要hello.s中出现的属于大作业PPT中P4给出的参考C数据与操作,都应解析。
3.3.1 函数参数传递
在hello.s 的main 函数中首先传入了两个参数argc,argv[], 这两个参数读入时被存于rdi 和rsi寄存器中,再通过下面两条指令存于用户栈上。
movl %edi, -20(%rbp)
movq %rsi, -32(%rbp)
3.3.2 数组
传入的参数argv[]即是一个指针数组,编译器对指针进行简单的加法来调用数组中不同的元素,在hello.s中,利用了如下指令取出了argv[1]及argv[2]
movq -32(%rbp), %rax
addq $16, %rax
movq (%rax), %rdx
movq -32(%rbp), %rax
addq $8, %rax
movq (%rax), %rax
3.3.3数据:常数和变量,赋值操作
在hello.s中定义了i变量,该变量存放于用户栈上,movl $0, -4(%rbp)将定义并赋值,常数存储于寄存器中,movl $1, %edi。
3.3.4条件控制及控制转移及关系操作
Hello.s中涉及到两个条件控制,一个是if判断语句,一个是for循环,编译器
利用了cmp和jump语句实现了条件控制及控制转移
在if中: cmpl $4, -20(%rbp)
je .L2
判断argc是否于与4相等,在根据结果跳转
在for中: cmpl $8, -4(%rbp)
jle .L4
判断i是否小于等于8,条件满足则跳转
3.3.5函数调用
编译器利用callq 指令完成对函数的调用,在hello.s中call puts@PLT,call exit@PLT,call printf@PLT,call atoi@PLT,call sleep@PLT,call getchar@PLT,完成了对不同函数的调用。
3.3.6算术操作
在hello.s中,编译器利用addl完成了加法运算,例如addl $1, -4(%rbp)完成了对i每次循环加1的操作。
3.4 本章小结
本章介绍了编译的概念及作用,完成了对hello.i的编译生成了hello.s 文件,并通过hello.s 的介绍,讲述了编译语言中的各种数据和操作。
(第3章2分)
第4章 汇编
4.1 汇编的概念与作用
汇编的概念:汇编器将汇编语言文件翻译为机器语言指令,生成.o(可重定位目标程序,二进制文件)。
汇编的作用:将汇编语言文件翻译为机器语言生成可重定位目标文件。
注意:这儿的汇编是指从 .s 到 .o 即编译后的文件到生成机器语言二进制程序的过程。
4.2 在Ubuntu下汇编的命令
应截图,展示汇编过程!
图4.1-汇编命令
上述为汇编的命令
图4.2-.o文件
生成的汇编文件如上
4.3 可重定位目标elf格式
分析hello.o的ELF格式,用readelf等列出其各节的基本信息,特别是重定位项目分析。
图4.3-readelf指令
使用上述指令展示各节基本信息
- elf头
图4.4-elf头内容
Elf头由一16字节的魔数开头包含了生成文件字长,字节序以及文件版本,文件类型等信息。
- 节头
图4.5-节头内容
节头包含了文件中出现的各个节的类型、地址、大小、偏移量等信息。
- 重定位节
图4.6-重定位节内容
重定位节包含了偏移量、信息、以及加数。
- 符号表节
图4.7-符号表节内容
符号表中包含了各个符号的编号、名称以及偏移量或者它的变量类型
4.4 Hello.o的结果解析
objdump -d -r hello.o 分析hello.o的反汇编,并请与第3章的 hello.s进行对照分析。
图4.8-反汇编结果内容
说明机器语言的构成,与汇编语言的映射关系。特别是机器语言中的操作数与汇编语言不一致,特别是分支转移函数调用等。
根据和hello.s 中的汇编语言对比分析,发现机器语言与汇编语言一一对应,但在一些地方,机器语言与汇编语言不同
- 操作数
汇编语言的操作数是由十进制表示,而机器语言的操作数是由十六进制表示。
- 分支转移
汇编语言的分支语言是跳转对应模块例如L1,L2等,而机器语言的分支转移是直接跳转对应地址如2f。
- 函数调用
汇编语言的函数调用指令跟着的是文件名,而机器语言后面跟着的是函数对应的地址。
4.5 本章小结
本章介绍了汇编的概念和作用,以及生成汇编文件的指令,再讲述了如何查看汇编文件的elf,展示了各个节的内容,最后通过反汇编介绍了汇编语言和机器语言的关系以及差异。
(第4章1分)
第5章 链接
5.1 链接的概念与作用
链接的概念:将各种代码和数据片段收集并组合成为一个单一文件的过程,这个文件可被加载(复杂)到内存并执行。
链接的作用:使分离编译成为可能,可以把一个大型程序分解为更小更好管理的模块,可以独立的修改和编译这些模块,当改变这些模块中的一个时,只需简单的重新编译它并重新链接就可以应用,不必重新编译其它文件。
注意:这儿的链接是指从 hello.o 到hello生成过程。
5.2 在Ubuntu下链接的命令
使用ld的链接命令,应截图,展示汇编过程! 注意不只连接hello.o文件
图5.1-链接命令
上述为链接命令
5.3 可执行目标文件hello的格式
分析hello的ELF格式,用readelf等列出其各段的基本信息,包括各段的起始地址,大小等信息。
图5.2-readelf指令
- elf头
图5.3-elf头的内容
对比.o文件的elf文件,发现类型从可重定位文件转为可执行文件了,而且节数从14变成了27。
- 节头
图5.4-节头内容
节头对比便是节数增多。
- 重定位节
图5.5-重定位节内容
- 符号表
图5.6-符号表内容
符号表多出了很多行内容,多了许多外部动态库的符号。
5.4 hello的虚拟地址空间
使用edb加载hello,查看本进程的虚拟地址空间各段信息,并与5.3对照分析说明。
图5.7-虚拟空间地址
虚拟地址空间分布与5.3中一致,401000地址与5.3中节表中的init函数(程序初始函数的地址一致。
5.5 链接的重定位过程分析
objdump -d -r hello 分析hello与hello.o的不同,说明链接的过程。
结合hello.o的重定位项目,分析hello中对其怎么重定位的。
图5.8-hello的反汇编
与hello.o对比,首先是多了很多外部函数,例如exit,printf,getchar等,也多了新的节例如init,plt。然后便是函数地址从之前的相对地址转换为了绝对地址,即确切地址。在进行条件控制时也是如此,从之前的相对地址变为了绝对地址。
链接的过程:
将各种代码和数据片段收集并组合成为一个单一文件的过程,这个文件可被加载(复杂)到内存并执行。
重定位的过程:
链接器在完成了符号解析这一步后,就把代码中的每个符号引用和正好一个符号定义关联起来。这时,链接器就知道它的输入目标模块中的代码节和数据节的确切大小。将合并输入模块,并为每个符号分配运行时的地址。例如链接器在解析已初始化的数据(如全局变量),便会根据.o文件的重定位条目将其放入.data中,并为其分配运行时的地址。
5.6 hello的执行流程
使用edb执行hello,说明从加载hello到_start,到call main,以及程序终止的所有过程。请列出其调用与跳转的各个子程序名或程序地址。
图5.9-子函数名及地址
上述为子函数名和其所在地址
5.7 Hello的动态链接分析
分析hello程序的动态链接项目,通过edb调试,分析在dl_init前后,这些项目的内容变化。要截图标识说明。
图5.10-动态链接库dl_init的起、止地址
图5.11-EDB项目
在dl_init调用之前,对于每一条PIC函数调用,调用的目标地址都实际指向PLT中的代码逻辑,GOT存放的是PLT中函数调用指令的下一条指令地址。
在dl_init调用之后,GOT[1]指向重定位表用来确定调用的函数地址, GOT[2]指向动态链接器ldlinux.so运行时地址。
5.8 本章小结
本章介绍了链接的概念及作用,链接的命令,分析了hello的elf、虚拟地址空间、重定位过程,以及执行流程和动态链接过程。
(第5章1分)
第6章 hello进程管理
6.1 进程的概念与作用
进程的概念:一个执行中程序的实例。
进程的作用:进程为用户提供了以下假象我们的程序好像是系统中当前运行的唯一程序一样,我们的程序好像是独占的使用处理器和内存,处理器好像是无间断的执行我们程序中的指令,我们程序中的代码和数据好像是系统内存中唯一的对象。
6.2 简述壳Shell-bash的作用与处理流程
作用: Shell是一个用C语言编写的程序,他是用户使用Linux的桥梁。Shell是指一种应用程序,Shell应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
处理流程:1.读取从键盘输入的命令
2.判断命令是否正确,且将命令行的参数改造为系统调用execve()内部处理所要求的形式
3.终端进程调用fork()_来创建子进程身身则用系统调用wait()来等待子进程完成
4. 子讲程运行时.它调用execve()根据命令的名字指定的文件到目录中查找可行性文件、调入内存并执行这个命令
5.命令行末尾有后台命令符号&终端进程不执行等待系统调用,而是立即发提示符,让用户输入下一条命令;如果命令末尾没有&则终端进程要一直等待。当子进程完成处理后,向父进程报告,此时终端进程被唤醒,做完必要的判别工作后,再发提示符,让用户输入新命令。
6.3 Hello的fork进程创建过程
输入./hello 2021110769 ghy 1000000后,shell对输入的命令进行判断,由于不是内置指令,shell判定其为一个可执行文件,调用fork() 函数创建一个子进程,这个子进程除了有着不同的PID外其他相同。
6.4 Hello的execve过程
fork()创建新进程后,shell的parseline函数回读取以空格分隔的参数-2021110769 ghy 100000,并将其作为参数传入execve中,execve函数便会加载并执行hello,而且将之前的参数作为argv[]变量,调用启动代码,启动代码设置用户栈并将控制传递给hello的主函数。
6.5 Hello的进程执行
结合进程上下文信息、进程时间片,阐述进程调度的过程,用户态与核心态转换等等。
进程调度的过程:在shell利用execve运行hello之后,系统内核保存了当前进程的上下文信息(系统重新启动该进程需要的状态),hello利用系统分配的进程时间片(分时操作系统分配给每个正在运行的进程微观上的一段CPU时间)来运行,在调用sleep后,进程被挂起,系统从用户态切换为核心态。
6.6 hello的异常与信号处理
hello执行过程中会出现哪几类异常,会产生哪些信号,又怎么处理的。
程序运行过程中可以按键盘,如不停乱按,包括回车,Ctrl-Z,Ctrl-C等,Ctrl-z后可以运行ps jobs pstree fg kill 等命令,请分别给出各命令及运行结截屏,说明异常与信号的处理。
异常:中断。
信号:SIGSTP,SIGINT,SIGKILL,SIGCHLD
信号处理:
- 不停乱按
图6.1-不停乱按的结果
- 回车
图6.2-输入回车的结果
- 输入ctrl+z
图6.3-ctrl+z以及相关指令
输入ctrl+z之后,收到SIGTSTP信号,将进程挂起,此时通过ps 等命令可以看到进程并未被回收。输入fg 1后,进程重新回到前台正常运行,输入kill-9 8793后发送SIGKILL信号强行杀死进程。
- 输入ctrl +c
图6.4输入ctrl+c指令
输入指令后,前台进程收到一个SIGINT信号,前台进程被终止,前台进程的父进程收到一个SIGCHLD信号,回收子进程,此时子进程不再存在。
6.7本章小结
本章介绍了进程的概念和作用,shell的作用和处理流程,hello的fork及execve过程,hello进程的运行过程,以及hello收到的各种信号和面对这些信号的处理。
(第6章1分)
第7章 hello的存储管理
7.1 hello的存储器地址空间
(以下格式自行编排,编辑时删除)
结合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动态存储分配管理
(以下格式自行编排,编辑时删除)
Printf会调用malloc,请简述动态内存管理的基本方法与策略。
7.10本章小结
(以下格式自行编排,编辑时删除)
(第7章 2分)
第8章 hello的IO管理
8.1 Linux的IO设备管理方法
(以下格式自行编排,编辑时删除)
设备的模型化:文件
设备管理:unix io接口
8.2 简述Unix IO接口及其函数
(以下格式自行编排,编辑时删除)
8.3 printf的实现分析
(以下格式自行编排,编辑时删除)
[转]printf 函数实现的深入剖析 – Pianistx – 博客园
从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall等.
字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。
显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。
8.4 getchar的实现分析
(以下格式自行编排,编辑时删除)
异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。
getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。
8.5本章小结
(以下格式自行编排,编辑时删除)
(第8章1分)
结论
用计算机系统的语言,逐条总结hello所经历的过程。
你对计算机系统的设计与实现的深切感悟,你的创新理念,如新的设计与实现方法。
过程:编译器通过预处理、编译、汇编、链接将程序从代码文件生成可执行文件。在shell中输入./hello后,shell就会调用fork()创建一个进程。
shell通过execve()加载程序,调用mmap使程序得以利用内存,通过CPU分配时间片使程序可以利用CPU的流水线。Os与mmu利用TLB、4级页表、3级Cache,Pagefile等方式为程序运行进行加速,IO管理能处理键盘、主板、显卡、屏幕的信号并使程序可以处理各种情况,最后程序运行完成后,shell回收这个进程。
感悟:计算机设计的精简,巧妙而又深奥。通过程序人生的作业,我对计算机系统中程序的运行进行了一次深入的探索,虽然很遗憾,由于课上并未教授虚拟地址以及IO管理等相关知识导致我对七八章无从下手,但在以后有时间的情况下我还会继续研读深入理解计算机系统,学习这方面的内容。
(结论0分,缺失 -1分,根据内容酌情加分)
附件
列出所有的中间产物的文件名,并予以说明起作用。
名字:hello.i,作用:代码文件经预处理后生成的文件
名字:hello.s, 作用:hello.i经编译后产生的文件,可以了解编译过程及汇编语言。
名字:hello.o, 作用;hello.s汇编后生成的文件,可用于链接以及对elf的查看
名字:hello,作用:hello.o链接后生成的文件
(附件0分,缺失 -1分)
参考文献
为完成本次大作业你翻阅的书籍与网站等
[1](美)布赖恩特(Bryant,R.E.)深入理解计算机系统 机械工业出版社
[2] www.baidu.com百度搜索
(参考文献0分,缺失 -1分)