计算机科学与技术学院
2021年5月
摘 要
本文通过分析一个简单的C语言程序在linux系统中从预处理到结束的全过程,加深我们对计算机系统的认识与理解。本文从hello的自白开始,对hello预处理、编译、汇编、链接、hello的进程管理、存储管理、IO管理等相关内容进行了深入的分析,并在linux系统上对该过程的每一步进行实验。最终使我们真正对hello的产生到回收的整个过程有了深刻的理解,从而让我们感受到学习计算机系统的意义和精髓所在。
关键词:linux;hello;预处理;编译;汇编;进程;存储
目 录
第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的预处理结果解析… – 6 –
2.4 本章小结… – 7 –
第3章 编译… – 9 –
3.1 编译的概念与作用… – 9 –
3.2 在Ubuntu下编译的命令… – 9 –
3.3 Hello的编译结果解析… – 9 –
3.4 本章小结… – 13 –
第4章 汇编… – 14 –
4.1 汇编的概念与作用… – 14 –
4.2 在Ubuntu下汇编的命令… – 14 –
4.3 可重定位目标elf格式… – 14 –
4.4 Hello.o的结果解析… – 17 –
4.5 本章小结… – 19 –
第5章 链接… – 20 –
5.1 链接的概念与作用… – 20 –
5.2 在Ubuntu下链接的命令… – 20 –
5.3 可执行目标文件hello的格式… – 20 –
5.4 hello的虚拟地址空间… – 22 –
5.5 链接的重定位过程分析… – 24 –
5.6 hello的执行流程… – 26 –
5.7 Hello的动态链接分析… – 28 –
5.8 本章小结… – 29 –
第6章 hello进程管理… – 30 –
6.1 进程的概念与作用… – 30 –
6.2 简述壳Shell-bash的作用与处理流程… – 30 –
6.3 Hello的fork进程创建过程… – 30 –
6.4 Hello的execve过程… – 31 –
6.5 Hello的进程执行… – 32 –
6.6 hello的异常与信号处理… – 33 –
6.7本章小结… – 37 –
第7章 hello的存储管理… – 38 –
7.1 hello的存储器地址空间… – 38 –
7.2 Intel逻辑地址到线性地址的变换-段式管理… – 38 –
7.3 Hello的线性地址到物理地址的变换-页式管理… – 39 –
7.4 TLB与四级页表支持下的VA到PA的变换… – 40 –
7.5 三级Cache支持下的物理内存访问… – 40 –
7.6 hello进程fork时的内存映射… – 40 –
7.7 hello进程execve时的内存映射… – 40 –
7.8 缺页故障与缺页中断处理… – 40 –
7.9动态存储分配管理… – 40 –
7.10本章小结… – 40 –
第8章 hello的IO管理… – 41 –
8.1 Linux的IO设备管理方法… – 41 –
8.2 简述Unix IO接口及其函数… – 41 –
8.3 printf的实现分析… – 41 –
8.4 getchar的实现分析… – 41 –
8.5本章小结… – 41 –
结论… – 42 –
附件… – 43 –
参考文献… – 44 –
第1章 概述
1.1 Hello简介
hello的整个过程指的是hello从程序员编写到在计算机系统里面运行所经历的一系列步骤。
首先P2P指的是:From Program to Process。即hello.c从程序变为进程的这个过程。
该过程一共分为以下6步:
- 程序员在文本编辑器里面写下hello的代码,并将其改为.c文件。hello的源程序便诞生,也是hello的文本文件。
- 接下来预处理器(cpp)通过对hello源程序中的头文件、宏定义等进行识别,对原程序进行一系列处理,得到一个新的文本文件hello.i。
- 编译器(ccl)将文本文件hello.i翻译成文本文件hello.s,里面存放的是一个汇编语言程序。
- 汇编器(as)继续将hello.s进行处理,得到二进制代码文件hello.o,即可重定位目标程序,需要进一步链接的处理。
- 最后链接器(ld)对hello.o进行符号解析和重定位,并最终输出二进制的可执行目标程序
- 程序员在shell中输入./hello 7203610730 ggt 3 ,shell对命令行内容进行识别,由于第一个字符串不是内置命令,故fork一个子进程,对hello进行加载,hello在子进程中运行
接下来020指的是:From Zero-0 to Zero-0,指的是hello从最开始没有空间到最后也被从进程中删除这一过程。在用户在Shell中敲下./hello之前按,hello不占用内存空间,即对应第一个0,接下来shell使用fork以及execve加载hello,然后mmap为其分配虚拟内存空间,接下来由Cache,CPU等硬件资源配合运行程序,直到进程结束。第二个0指的是在进程结束后,hello进程会被父进程回收,并由内核删除相关的数据结构,最终hello不再占用内存空间。
1.2 环境与工具
硬件:处理器:AMD Ryzen 7 4800H with Radeon Graphics 2.90 GHz
RAM : 16GB 系统类型:64 位操作系统, 基于 x64 的处理器
软件 Windows10 64位
Ubuntu 20.04.4
开发与调试工具:vscode,Visual Stdio,2022 ,gcc,edb,gedit
1.3 中间结果
列出你为编写本论文,生成的中间结果文件的名字,文件的作用等。
表格 1 中间产物
文件名 | 作用 |
hello.i | hello.c预处理后得到的文件 |
hello.s | 编译后的汇编语言文件 |
hello.o | 汇编后得到的可重定位目标文件 |
hello.elf | 用readelf读取hello.o得到的ELF格式信息 |
Dhello.s | 反汇编hello.o得到的反汇编文件 |
helloout.elf | 由hello可执行文件生成的.elf文件 |
Dhelloout.s | 反汇编hello可执行文件得到的反汇编文件 |
hello | 最终链接得到的可执行文件 |
1.4 本章小结
(第1章0.5分)
本章首先讲述了Hello的P2P,020的整个过程的具体含义,然后介绍了完成该论文时所采用的环境与工具以及生成的中间结果。
第2章 预处理
2.1 预处理的概念与作用
预处理的概念:
预处理是指编译器在读取源程序后,在真正的编译开始之前,预处理器(cpp)根据以字符#开头的命令,修改原始的C程序。主要包括宏定义、文件包含、条件编译三方面的内容。例如hello.c程序的第6、7、8行#include ,#include ,#include 命令告诉预处理器读取系统头文件 stdio.h、unistd.h、stdlib.h中的内容